1.Vue框架是什么?
Vue是一款以响应式数据为核心驱动页面渲染的Web页面渲染引擎,在Vue框架中一切响应式的数据变化都可以驱动视图更新。同时Vue框架使用虚拟DOM的方式异步的执行视图更新。
2.vue生命周期?
总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
创建前/后: 在beforeCreate阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el为undefined,还未初始化。
载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:当data变化时,会触发beforeUpdate和updated方法
销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
3.Vue框架和传统的DOM框架对比,有何区别?
DOM
遍历DOM树获取DOM对象;确认需要操作的视图属性;更改对象的属性触发视图更新,视图执行一次更新;
Vue
初始化框架构建虚拟DOM树,将响应式数据对象映射到虚拟DOM树中。更改需要更新的属性,将更新队列中的任务一次进入虚拟DOM中,将虚拟DOM中需要变更的部分一次设置到DOM对象中。
总结
通过对比得知传统的DOM框架采用的视图更新机制是同步方式进行的,所以一旦涉及到操作DOM属性就会触发DOM树进行一次渲染,当页面有N步数据更新的时候就算N步数据是同时改的,视图部分也会进行N次渲染。
而Vue框架是采用非直接DOM操作的方式进行页面渲染,这样可以将视图更新时的多次更改放到一个任务队列中,最终将本次更改的N次变化统一由一次渲染替代真实的DOM对象,这样可以实现N次变更,一次渲染。在性能上更优于传统的DOM框架。
4.为什么vue组件中data必须是一个函数?
对象为引用类型,当复用组件时,由于数据对象都指向同一个data对象,当在一个组件中修改data时,其他重用的组件中的data会同时被修改;而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题。
5.Vue响应式数据模式指的是什么?
Vue框架的核心特点就是他的响应式数据。Vue的响应式数据系统也叫做MVVM架构。
MVVM介绍
MVVM分为三个部分:分别的M(Model,模型层),V(View,视图层),VM(ViewModel,V与M连接的桥梁,也可以看作控制器)。
M:模型层,主要负责业务数据相关;
V:视图层,负责视图相关;
MV:V与M沟通的桥梁,负责监听M或者V的修改,是实现MVVM双向数据绑定的要点。
6.vue中v-if和v-show有什么区别?
v-if和v-show看起来似乎差不多,当条件不成立时,其所对应的标签元素都不可见,但是这两个选项是有区别的:
1、v-if在条件切换时,会对标签进行适当的创建和销毁,而v-show则仅在初始化时加载一次,因此v-if的开销相对来说会比v-show大。
2、v-if是惰性的,只有当条件为真时才会真正渲染标签;如果初始条件不为真,则v-if不会去渲染标签。v-show则无论初始条件是否成立,都会渲染标签,它仅仅做的只是简单的CSS切换。
7.Vue2的属性更新限制和解决方案有哪些?
当我们使用VM对象更新userInfo 中初始化就存在的属性时,视图会自动触发更新,而当我们对userInfo 内部不存在的属性设置值的时候视图不更新,这是因为Vue2.x 底层的数据响应式系统使用的是Object.defineProperty()来实现的,
Vue 在初始化的时候会递归的将data选项中的属性绑定 setter 和 getter,通过两者来观察属性的行为,一旦初始化完成便不会再次执行本操作,所以更改已知属性的时候Vue实例是有感知并执行默认处理行为的,当我们操作对象内部不存在的属性时,由于其没有setter 和 getter ,Vue 将无法观察到这些属性的赋值和取值,视图更新操作也无法进行。
解决方案
1. $set(obj,key,value)---- 推荐
针对Vue2.x 底层能力限制,后定义的属性由于没有在初始化时绑定监听,所以Vue 无法捕捉后定义属性的行为,为了弥补这种场景无法触发视图更新的问题,Vue 在实例上提供了一个$set函数,用来辅助更新视图
2.&forceUpdate() --- 不推荐
除了$set 之外,Vue 还提供了一个API 名为 &forceUpdate 来实现视图的更新,它同样挂载在Vue 的实例对象上,不同于 $set ,&forceUpdate不需要指定要更新的属性,他会在执行的时候强制Vue 实例重新执行一次渲染,这样视图层所有的内容都会重新执行一次更新,在这之前的如果有后定义的属性进行更改同样也会体现在视图上,这种方式只适用于特殊场景否则会让渲染性能开销增大。 VM.&forceUpdate()
8.computed和watch的区别
计算属性computed:
支持缓存,只有依赖数据发生改变,才会重新进行计算
不支持异步,当computed内有异步操作时无效,无法监听数据的变化
computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
侦听属性watch:
不支持缓存,数据变,直接会触发相应的操作;
watch支持异步;
监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
当一个属性发生变化时,需要执行对应的操作;一对多;
监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数:
9.$nextTick是什么?
vue实现响应式并不是数据发生变化后dom立即变化,而是按照一定的策略来进行dom更新。
nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用nextTick,则可以在回调中获取更新后的 DOM
10.v-for key的作用
当Vue用 v-for 正在更新已渲染过的元素列表是,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue将不是移动DOM元素来匹配数据项的改变,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。key属性的类型只能为 string或者number类型。
key 的特殊属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes。如果不使用 key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用key,它会基于key的变化重新排列元素顺序,并且会移除 key 不存在的元素。
11.封装 vue 组件的过程
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性等问题。
然后,使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。
12.组件传值
父传子 (通过props传递)
//子组件 Child.vue
<template>
<div id="container">
{{msg}}
</div>
</template>
<script>
export default {
data() {
return {};
},
props:{
msg: String
}
};
</script>
<style scoped>
#container{
color: red;
margin-top: 50px;
}
</style>
//父组件
<template>
<div id="container">
<input type="text" v-model="text" @change="dataChange">
<Child :msg="text"></Child>
</div>
</template>
<script>
import Child from "@/components/Child";
export default {
data() {
return {
text: "父组件的值"
};
},
methods: {
dataChange(data){
this.msg = data
}
},
components: {
Child
}
};
</script>
子传父(this.$emit )
//子组件
<template>
<div id="container">
<input type="text" v-model="msg">
<button @click="setData">传递到父组件</button>
</div>
</template>
<script>
export default {
data() {
return {
msg: "传递给父组件的值"
};
},
methods: {
setData() {
this.$emit("getData", this.msg);
}
}
};
</script>
<style scoped>
#container {
color: red;
margin-top: 50px;
}
</style>
//父组件
<template>
<div id="container">
<Child @getData="getData"></Child>
<p>{{msg}}</p>
</div>
</template>
<script>
import Child from "@/components/Child";
export default {
data() {
return {
msg: "父组件默认值"
};
},
methods: {
getData(data) {
this.msg = data;
}
},
components: {
Child
}
};
</script>
兄弟组件传值
//bus.js
import Vue from 'vue';
export default new Vue();
<template>
<div>
<h2>这是demo01组件</h2>
<button @click="add"> 点击向dome02组件发送消息 </button>
</div>
</template>
<script>
import Bus from '../utils/bus'
export default {
methods:{
// 点击按钮发送Bus消息
add(){
// 发送 myMsg 主题 的Bus消息
Bus.$emit('myMsg', "你好啊,我叫XXX");
// 打印一下日志
console.log("dome01组件发送完消息:bus事件触发了")
}
}
}
</script>
<template>
<div>
<h2>这是dome02组件</h2>
<h3>这个地方展示dome01组件的命令</h3>
<!-- 把 dome01 发过来的消息渲染到下面 -->
<span>{{msg}}</span>
</div>
</template>
<script>
// 引入bus.js文件
import Bus from '../utils/bus'
export default {
data() {
return {
msg: "XXX"
};
},
// 在mounted钩子里面就开始定阅myMsg主题的消息
mounted() {
Bus.$on('myMsg', myMsg => {
console.log("dome02组件收到bus消息:",myMsg);
this.msg = myMsg
});
}
};
</script>
13.class绑定?
class 绑定一般为对象或者是数组
class 绑定不会覆盖原始标签的class
<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
<script>
data(){
return {
data: {
isActive: true,
hasError: false
}
}
}
</script>
<div v-bind:class="[activeClass, errorClass]"></div>
<script>
data(){
return {
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
}
}
</script>
14.vue如何获取dom
先给标签设置一个ref值,再通过this.$refs.domName获取,例如:
<div ref="app"></div>
const dom = this.$refs.app
15.v-on可以监听多个方法吗?
<input type="text" v-on="{ input:onInput,focus:onFocus,blur:onBlur, }">
16.slot插槽
有时,我们封装了一个子组件之后,在父组件使用的时候,想添加一些dom元素,这个时候就可以使用slot插槽了,但是这些dom是否显示以及在哪里显示,则是看子组件中slot组件的位置了。
17.vue初始化页面闪动问题
在vue初始化之前,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是这个问题还是可以再优化的。在css中添加如下代码。
[v-cloak] {
display: none;
}
18.在Vue对象中存在 createApp 方法(vue3.x)
const app = Vue.createApp({
data(){
return {}
}
//渲染函数使用mount而非 $mount
}).mount('#app')
//输出app会发现它是一个 Proxy 对象,所以 Vue3 中的数据响应式系统显然时代理对象
console.log(app)
Vue3.x 主要更新的内容是重构依赖库的依赖关系,并且对 TS 的类型检测做个完整的支持,在原始基础上重构了数据响应式系统,增加了函数式编程的新开发策略,其他总体上更新更趋近 React 框架,现在的 Vue 与 React 很像,既可以使用对象编程的方式也可以使用函数编程的方式,两种可以并存。