【前端面试题——vue3篇】(三)

简介: 【前端面试题——vue3篇】(三)

【前端面试题——vue3篇】(二)https://developer.aliyun.com/article/1399412?spm=a2c6h.13148508.setting.33.7c824f0eej0yJq


31.vue插槽?

slot又名插槽,是vue的内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口。插槽slot是子组件的一个模板标签元素,而在一个标签元素是否显示,以及怎么显示是父组件决定的。slot又分为三类,默认插

槽,具名插槽,作用域插槽。


默认插槽:又称匿名插槽,当slot没有指定name属性值的时候,一个组件内只能有一个匿名插槽。

具名插槽:带有具体名字的插槽,也就是带有name属性的slot,一个组件可以出现多个具名插槽。

作用域插槽:默认插槽,剧名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,作用域插槽数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定,也就是说,作用域插槽的不同之处就在于,数据不在父组件身上,而是在子组件身上,且组件的结构和内容由父组件决定。作用域组件限定了组件内结构和数据的展示范围,以便在开发中我们可以根据一个组件而不断变换其中的内容和结构。


32.vue3中如何获取refs,dom对象的方式?

方式一:setup函数方法内,获取单个ref属性绑定的dom元素


  • 先定义一个空的响应式数据ref定义的
  • setup中返回该数据,你想获取哪个dom元素,在该元素上使用ref属性绑定该数据即可


<template>
  <h1 ref="box">Ref属性获取dom</h1>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
    setup () {
        let box = ref(null)
        onMounted(function () {
            console.log(box.value);
        })
        return {
            box
        }
    }
}
</script>


方式二:获取多个ref属性绑定的dom元素。


  • 使用ref绑定一个函数,在函数里把dom添加到数组里面


<template>
  <h3 :ref="getlist" v-for="index in 3">我是一组元素{{index}}</h3>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
    name: 'Ref',
    setup () {
        // 获取v-for遍历的元素
        // 定义一个空数组,接收所有的LI
        // 定义一个函数,往空数组push Dom
        let listDom = []
        const getlist = (el) => {
            listDom.push(el)
        }
        console.log(listDom);
        return {
            getlist
        }
    }
}
</script>


总结:


  • 单个元素: 先声明ref响应式数据,返回给模板使用,通过ref绑定数据


  • 遍历的元素:先定义一个空数组,定一个函数获取元素,返回给模板使用,通过ref绑定这个函数


33.vue3中生命周期的和vue2中的区别?

vue2.0生命周期:

创建阶段

beforeCreate()创建前阶段,这个时候还不能使用data中的数据。

created()创建完成 最早可以使用data中的数据

挂载阶段

beforeMount:在挂载开始之前被调用: 相关的 render 函数首次被调用

mounted: 挂载完成,DOM节点挂载到实例上去之后调用该钩子

更新阶段

beforeUpdate:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。

updated: 数据更新完成并且DOM更新完成后调用销

销毁阶段

beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用

destroved:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定


vue3.0


  • 去掉了vue2.0中的 beforeCreate 和 created 两个阶段,同样的新增了一个 setup
  • beforeMount 挂载之前 改名 onBeforeMount
  • mounted 挂载之后 改名 onMounted
  • beforeUpdate 数据更新之前 改名 onBeforeUpdate
  • updated 数据更新之后 改名 onUpdated
  • beforeDestroy 销毁前 改名 onBeforeUnmount,可在此进行清除定时器,进行事件监听,发布订阅。
  • destoryed 销毁后 改名 onUnmounted
  • errorCaptured 报错 改名 onErrorCaptured


总结

不难发现3.0中钩子函数最大的变化就是setup代替了2.0中的beforeCreate和created,而对应其它几个函数来说都是名称上发生了一些变化,其功能基本上还是一样的。


34.说说vue中的diff算法?

点击查看


35.说说 Vue 中 CSS scoped 的原理?

在vue文件中的style标签上,有一个特殊的属性:scoped。当一个style标签拥有scoped属性时,它的CSS样式就只能作用于当前的组件,也就是说,该样式只能适用于当前组件元素。通过该属性,可以使得组件之间的样式不互相污染。如果一个项目中的所有style标签全部加上了scoped,相当于实现了样式的模块化。


vue中的scoped属性的效果主要通过PostCSS转译实现


PostCSS给一个组件中的所有dom添加了一个独一无二的动态属性,然后,给CSS选择器额外添加一个对应的属性选择器来选择该组件中dom,这种做法使得样式只作用于含有该属性的dom——组件内部dom。


36.vue3中怎么设置全局变量?

在vue2中,我们知道vue2.x是使用Vue.prototype.xxxx = xxx 来定义全局变量,然后通过 this . xxxx=xxx来定义全局变量,然后通过this.xxxx=xxx来定义全局变量,然后通过this.xxx来获取全局变量。


但是在vue3中,这种方法显然不行了。因为vue3中在setup里面我们是无法获取到this的。


vue3.0依赖注入的方式注册使用全局变量

在 main.js 中


const app = createApp(App)
// 配置全局变量 页面中使用 inject 接收
app.provide('global',{
  store,
  axios
})
app.use()进行使用


采用这种方法在全局变量的创建上会更加的方便 , 而且不用担心会出现像axios在使用globalProperties设置为全局对象后丢失axios对象只剩 axios对象只剩axios对象只剩http之类的问题


vue3.0store仓库进行存放全局变量

创建store文件夹

store文件夹下创建index文件

state中定义状态或数据


const store = createStore({
    state () {
        return {
            base:"",//基本数据
        }
    },
    mutations: {
        /*修改基础数*/
        changeBase(state,base) {
            state.base=base;
        },
    }
})
export default store;


37.Vue中给对象添加新属性时,界面不刷新怎么办?

vue2的响应式原理使用的是对象代理去实现的,对象代理中有一个get和set方法,当我们访问对象的时候就会触发get方法,当我们对对象中的值进行修改时会触发set方法。但是当我们给对象添加一个新的属性时对象代理是检测不到的,所以就会出现直接给对象添加属性响应式不生效的问题。

所以在vue中可以使用this.$set(对象名,‘属性名’,属性值)的方法去给对象添加属性,或者使用Vue.set(对象名,‘属性名’,属性值)的方法进行添加,添加之后的属性就带有响应式了


38.谈谈对Vue中双向绑定的理解?

vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;

VUE双向数据绑定,其核心是 Object.defineProperty()方法,给Vue中的数据绑定get和set方法,当获取数据的时候,调用get方法,修改data中的数据的时候调用set方法,通过watcher监听器去更新视图,完成数据的双向绑定。


1、需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,

给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化。


2、compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定

更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。


3、watcher订阅者是observer和compile之间通信的桥梁,主要做的事情是:1*.在自身实例化时往属性订阅器里面添加自己2*.组件自身必须有一个update()方法.3*待属性变动dep.notice()通知时,能调用自身的update()方法,

并触发complie中绑定的回调,则功成身退。


4、MVVM作为数据绑定的入口,整合observer、compile和watcher三者,通过observer来监听自己的model数据变化,通过compile来解析编译模板指令,最终利用watcher搭起来Observer和Compile之间的通信桥梁,达到数据变化,视图更新,视图交互话变化,数据model变更的双向绑定效果。


39.为什么vue2和vue3语法不可以混用?

优先级:

出现重名自变量,会根据书写顺序进行页面的展示。

vue2中的data和vue3中的setup


40.vue3中setup函数如何进行组件通讯?

setup语法糖方式通信:


父传子——defineProps


1.父组件使用子组件,在子组件标签里面,通过标签属性的方式进行数据传递
  <template>
    <children :list="list"></children>
  </template>
  2.在子组件引入import { defineProps } from 'vue'
    <script setup>
   import { defineProps } from 'vue'
  const props = defineProps({
        list: {
         type: Array,
         default: () => []
        }
      })
    </script>
    defineProps方法定义变量名进行接收,template模板中进行使用。


子传父——defineEmits


父组件在子组件标签上通过v-on绑定自定义事件,子组件通过 const emits = defineEmits([‘事件名’])进行接收。

在子组件B中通过defineEmits注册一个事件名,然后在子组件B的方法中通过emit传递给父组件A。在组件A中,就可以为一些元素添加该事件名绑定事件方法。然后组件A在script setup中写这个事件方法,传递的参数就是子组件B在emit传递过来的值。这个值我们赋值给const的ref定义的数据,从而动态修改数据。


<template>
    <div>
       <input v-model="value" type="text" placeholder="请输入" />
       <button @click="handleAdd"> 添加 </button>
     </div>
    </template>
    <script setup>
     import { ref, defineEmits } from 'vue'
     const value = ref('')
     const emits = defineEmits(['add'])
     const handleAdd = () => {
       emits('触发的方法', 传递的参数)
     }
    </script>


setup函数嵌套方式通信


父传子props


父组件中使用子组件的标签
 在 子组件 setup 方法内使用props 来接收父组件传过来的数据。
  <template>
    <div>
      <Article :msg="name"></Article>
    </div>
  </template>
  <script>
  import Article from '@/components/Article.vue' 
  export default {
    components: {
      Article
    },
    setup() {
      return {
        name: '渐行渐远渐无书,水阔鱼沉何处问'
      }
    }
  }


子传父 content


<template>
  <div>
    {{msg}}
    <button @click="sendToParent">子组件向父组件传递数据</button>
  </div>
</template>
<script>
export default {
  props:['msg'],
  setup(props, content) {
    console.log(props.msg)
    function sendToParent() {
      content.emit('change')
    }
    return {
      sendToParent
    }
  }
}
</script>


41.vue3,Composition API 的优势?

Composition

在 Vue3 Composition API 中,组件根据逻辑功能来组织的,一个功能所定义的所有 API 会放在一起(更加的高内聚,低耦合),即使项目很大,功能很多,我们都能快速的定位到这个功能所用到的所有 API,Compositon API,将某个逻辑关注点相关的代码全都放在一个函数里,这样当需要修改一个功能时,就不再需要在文件中跳来跳去。


composition APi:

  • setup

Vue3.0中一个新的配置向,值为一个函数

setup是所有Composition API(组合API) ”表演的舞台“

组件中所有用到的:数据、方法等等,均要配置在setup中


  • setup语法糖

语法糖里面的代码会被编译成组件setup()函数的内容,不需要通过return暴露声明的变量、函数以及import引入的内容,即可在template使用,并且不需要export default{}


  • ref函数

作用:定义一个响应式的数据。

基本类型的数据:响应式依然是靠Object.defineProperty()的get和set完成的

对象类型的数据:内部“求助”了Vue3.0的一个新的函数------reactive函数


  • reactive函数

作用:定义一个对象类型的响应式数据


  • defineEmits

setup语法糖中引入defineEmits方法,传入数组,数组里面则是父组件传递的自定义事件名。


  • 自定义hooks

ve3中还可以自定义 hooks, 将单个功能封装成单个的函数,在集成到组件中去复用! 将功能进行解耦,方便维护、复用、可读性强


42.shallowReactive和shallowRef的区别

shallowReactive:只处理对象最外层的响应式(浅响应式)。

shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理。


43.provide与inject如何使用

概述:父子组件传参可以通过props和emit来实现,但是当组件的层次结构比较深时,props和emit就没什么作用了。vue为了解决这个提出了Provide / Inject;provider/inject:简单的来说就是在父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量.


作用:实现祖和后代组件间通信。


provide()函数

定义:提供一个值,可以被后代组件注入。


具体实现

父组件有一个provide选项提供数据,后代组件有一个inject选项来开始使用这些数据。

provide(第一个参数是要注入的key,它可以是一个字符串或一个symbol;第二个参数是要注入的值(具体要传递给子孙组件的数据)。


import {reactive,provide} from "vue"; 
let person = reactive({name: '张三',age: 14});
provide('person',person);


inject()函数

定义: 注入一个由祖先(父)组件或整个应用提供的值

实现: 接收父(祖)组件传递过来的值.

inject(第一个参数,第二个参数(可选)):第一个参数是注入的key,来自父(祖)组件,它们两者是需要保持一致的


Vue会遍历父组件链,通过匹配key来确定所提供的值,如果父组件链上多个组件对同一个key提供了之,那么离得更近的将会覆盖链上更远的组件所提供的值


如果没有能通过key匹配到的值,inject()函数将返回undefined,除非提供一个默认值


第二个参数是可选的,即没有匹配到key时,使用默认值,它也可以是一个函数,用来返回某些创建起来比较复杂的值,如果默认值本身就是一个函数


那么必须将false作为第三个参数传入,表明这个函数就是默认值,而不是一个工厂函数。


与注册生命周期钩子的API类似,inject()必须在组件的setup()阶段同步调用


import {inject,toRefs} from  "vue";
const person = inject('person');
// 若是使用解构,则会丢失响应式,修改数据时,页面不会更新,具体解决,可以引入toRef或toRefs函数
const {name,website} = toRefs(person);
模板使用
{{person.name}}---{{person.website}}


总结

provide/inject 做全局状态管理的原则:

多人协作时,做好作用域隔离;

尽量使用一次性数据作为全局状态


44.toRaw 与 markRaw是什么作用?

  • toRaw

作用:将一个由reactive生成的响应式对象转化为普通对象。

使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新.


  • markRaw

作用:标记一个对象,使其永远不会再成为响应式对象。

应用场景:

1.有些值不应被设置为响应式的,例如复杂的第三方类的库。

2.当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。


45.readonly 与 shallowReadonly谈谈你对他的理解?

  • readonly: 让一个响应式数据变为只读的(深只读)。

readonly是一个函数,他会接收一个响应式的数据,如上定义的name变量,将该变量加工一番readonly函数

包裹后后重新返回一个name,这个重新返回的name变量中的所有的东西都不允许修改,所以我们现在再

点击上面的修改按钮 name 变量也不会有任何改变,并且控制台会有警告。


  • shallowReadonly:让一个响应式数据变为只读的(浅只读)。

shallowReadonly只限制对象中的第一层数据(不能改动,如:salary),但是嵌套的深层次的value属性值

是可以更改的,我们点击更改按钮测试就能发现,被shallowReadonly包裹的对象的深层次值改变了。


46.自定义hook是什么?

在 Vue 3 中,Hook 是通过 Vue 3 新特性的最重要的部分——组合式 API 来实现的.

本质是一个函数。自定义hook,就是将setup中使用过的组合式函数进行封装,实现代码复用。

把数据、方法、和生命周期钩子封装在一个js文件。

在src目录下新建子目录hooks,并在hooks目录下新建文件:usePoint.js


47.虚拟DOM一定更快吗?

虚拟DOM/domDiff


我们常说的虚拟DOM是通过JS对象模拟出来的DOM节点,domDiff是通过特定算法计算出来一次操作所带来的DOM变化。react和vue中都使用了虚拟DOM,我们借着react聊聊虚拟DOM。


react中涉及到虚拟DOM的代码主要分为以下三部分,其中核心是第二步的domDiff算法:


把render中的JSX(或者createElement这个API)转化成虚拟DOM

状态或属性改变后重新计算虚拟DOM并生成一个补丁对象(domDiff)

通过这个补丁对象更新视图中的DOM节点


虚拟DOM不一定更快

干前端的都知道DOM操作是性能杀手,因为操作DOM会引起页面的回流或者重绘。相比起来,通过多一些预先计算来减少DOM的操作要划算的多。


但是,“使用虚拟DOM会更快”这句话并不一定适用于所有场景。例如:一个页面就有一个按钮,点击一下,数字加一,那肯定是直接操作DOM更快。使用虚拟DOM无非白白增加了计算量和代码量。即使是复杂情况,浏览器也会对我们的DOM操作进行优化,大部分浏览器会根据我们操作的时间和次数进行批量处理,所以直接操作DOM也未必很慢。


那么为什么现在的框架都使用虚拟DOM呢?因为使用虚拟DOM可以提高代码的性能下限,并极大的优化大量操作DOM时产生的性能损耗。同时这些框架也保证了,即使在少数虚拟DOM不太给力的场景下,性能也在我们接受的范围内。


而且,我们之所以喜欢react、vue等使用了虚拟DOM框架,不光是因为他们快,还有很多其他更重要的原因。例如react对函数式编程的友好,vue优秀的开发体验等,目前社区也有好多比较这两个框架并打口水战的,我觉着还是在两个都懂的情况下多探究一下原理更有意义一些


48.vue路由中,history和hash两种模式有什么区别?

  • history模式

history API 是 H5 提供的新特性,允许开发者直接更改前端路由,即更新浏览器 URL 地址而不重新发起请求。


<a href="javascript:toA();">A页面</a>
<a href="javascript:toB();">B页面</a>
<div id="app"></div>
<script>
  function render() {
    app.innerHTML = window.location.pathname
  }
  function toA() {
    history.pushState({}, null, '/a')
    render()
  }
  function toB() {
    history.pushState({}, null, '/b')
    render()
  }
  window.addEventListener('popstate', render)
</script>


history API 提供了丰富的函数供开发者调用:


history.replaceState({}, null, '/b') // 替换路由
history.pushState({}, null, '/a') // 路由压栈
history.back() // 返回
history.forward() // 前进
history.go(-2) // 后退2次


history 模式的优缺点:

优点:路径比较正规,没有井号 #

缺点:兼容性不如 hash,且需要服务端支持,否则一刷新页面就404了。


  • hash模式

hash 模式是一种把前端路由的路径用井号 # 拼接在真实 URL 后面的模式。当井号 # 后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发 hashchange 事件。


<script>
<a href="#/a">A页面</a>
<a href="#/b">B页面</a>
<div id="app"></div>
<script>
  function render() {
    app.innerHTML = window.location.hash
  }
  window.addEventListener('hashchange', render)
  render()
</script>


在上面的例子中,我们利用 a 标签设置了两个路由导航,把 app 当做视图渲染容器,当切换路由的时候触发视图容器的更新,这其实就是大多数前端框架哈希路由的实现原理。


hash 模式的优缺点:

优点:浏览器兼容性较好,连 IE8 都支持

缺点:路径在井号 # 的后面,比较丑。

相关文章
|
2月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
190 2
|
1月前
|
资源调度 前端开发 JavaScript
vite3+vue3 实现前端部署加密混淆 javascript-obfuscator
【11月更文挑战第10天】本文介绍了在 Vite 3 + Vue 3 项目中使用 `javascript-obfuscator` 实现前端代码加密混淆的详细步骤,包括安装依赖、创建混淆脚本、修改 `package.json` 脚本命令、构建项目并执行混淆,以及在 HTML 文件中引用混淆后的文件。通过这些步骤,可以有效提高代码的安全性。
|
1月前
|
前端开发 JavaScript 开发者
React与Vue:前端框架的巅峰对决与选择策略
【10月更文挑战第23天】React与Vue:前端框架的巅峰对决与选择策略
|
1月前
|
前端开发 JavaScript 数据管理
React与Vue:两大前端框架的较量与选择策略
【10月更文挑战第23天】React与Vue:两大前端框架的较量与选择策略
|
1月前
|
缓存 前端开发 JavaScript
"面试通关秘籍:深度解析浏览器面试必考问题,从重绘回流到事件委托,让你一举拿下前端 Offer!"
【10月更文挑战第23天】在前端开发面试中,浏览器相关知识是必考内容。本文总结了四个常见问题:浏览器渲染机制、重绘与回流、性能优化及事件委托。通过具体示例和对比分析,帮助求职者更好地理解和准备面试。掌握这些知识点,有助于提升面试表现和实际工作能力。
66 1
|
1月前
|
JavaScript 前端开发 搜索推荐
Vue的数据驱动视图与其他前端框架的数据驱动方式有何不同?
总的来说,Vue 的数据驱动视图在诸多方面展现出独特的优势,其与其他前端框架的数据驱动方式的不同之处主要体现在绑定方式、性能表现、触发机制、组件化结合、灵活性、语法表达以及与后端数据交互等方面。这些差异使得 Vue 在前端开发领域具有独特的地位和价值。
|
2月前
|
JavaScript 前端开发 算法
前端优化之超大数组更新:深入分析Vue/React/Svelte的更新渲染策略
本文对比了 Vue、React 和 Svelte 在数组渲染方面的实现方式和优缺点,探讨了它们与直接操作 DOM 的差异及 Web Components 的实现方式。Vue 通过响应式系统自动管理数据变化,React 利用虚拟 DOM 和 `diffing` 算法优化更新,Svelte 通过编译时优化提升性能。文章还介绍了数组更新的优化策略,如使用 `key`、分片渲染、虚拟滚动等,帮助开发者在处理大型数组时提升性能。总结指出,选择合适的框架应根据项目复杂度和性能需求来决定。
|
2月前
|
监控 JavaScript 前端开发
前端的混合之路Meteor篇(六):发布订阅示例代码及如何将Meteor的响应数据映射到vue3的reactive系统
本文介绍了 Meteor 3.0 中的发布-订阅模型,详细讲解了如何在服务器端通过 `Meteor.publish` 发布数据,包括简单发布和自定义发布。客户端则通过 `Meteor.subscribe` 订阅数据,并使用 MiniMongo 实现实时数据同步。此外,还展示了如何在 Vue 3 中将 MiniMongo 的 `cursor` 转化为响应式数组,实现数据的自动更新。
|
2月前
|
前端开发 JavaScript 安全
在vue前端开发中基于refreshToken和axios拦截器实现token的无感刷新
在vue前端开发中基于refreshToken和axios拦截器实现token的无感刷新
160 4
|
1月前
|
前端开发 JavaScript 安全
vite3+vue3 实现前端部署加密混淆 javascript-obfuscator
【11月更文挑战第7天】本文介绍了在 Vite 3 + Vue 3 项目中使用 `javascript-obfuscator` 实现前端代码加密混淆的详细步骤。包括项目准备、安装 `javascript-obfuscator`、配置 Vite 构建以应用混淆,以及最终构建项目进行混淆。通过这些步骤,可以有效提升前端代码的安全性,防止被他人轻易分析和盗用。
241 0