1、Vue是什么
Vue是一套用于构建用户界面的渐进式框架
2、Vue优缺点
优点:渐进式,组件化,轻量级,虚拟dom,响应式,单页面路由,数据与视图分开
缺点:spa不利于Seo优化,不支持IE8以下,首屏加载时间长
3、Vue & React区别
相同点:spa、虚拟dom、组件化、单向数据流、ssr
不同点:
Vue模板语法,React jsx语法
Vue响应式处理数据,React手动(setState)
React单向数据绑定 , Vue双向数据绑定
React用redux , Vue用Vuex
4、MVVM是什么?和MVC有何区别呢?
5、Vue中当前组件所有属性快速传递给子组件
v-bind
6、Vue修饰符
7、Vue内置指令
8、组件之间的传值方式有哪些?
1、父传子:
子组件用props接收
2、子传父:
通过
this.$emit(‘xxxxx’,paload)$refs 获取组件实例
3、兄弟组件:
eventbus处理
通过公共上层组件传递
4、使用Vuex全局状态管理
5、本地缓存
9、Eventbus原理及优缺点
核心
export default EventBus = new Vue(),通过创建一个Vue实例来存储需要通信的数据。通过发布订阅者模式,完成数据传递
EventBus.$on("bMsg", (msg) => { this.msg = msg;}); //接收数据
EventBus.$emit("aMsg", '要发送的数据'); //发送数据
优点:
可以解决层层嵌套或同级组件数据传递的痛点
缺点:
Vue是Spa单页应用,当某页面刷新,与之关联的bus也会被清除
如果业务有反复操作的页面,EventBus在监听的时候就会触发很多次,也是一个非常大的隐患。这时候我们就需要好好处理EventBus在项目中的关系。通常会用到,在Vue页面销毁时,同时移除EventBus事件监听。
由于是都使用一个Vue实例,所以容易出现重复触发的情景,两个页面都定义了同一个事件名,并且没有用$off销毁(常出现在路由切换时)。
10、v-if和v-show有何区别?
-
相同点:
都能控制元素显隐
-
不同点:
1、v-if 为false的时候会直接
销毁
当前元素;
2、v-show为false的时候指示隐藏了当前元素,类似
display:none; -
故频繁或者大数量显隐使用
v-show,否则使用v-if
11、为什么v-if和v-for不建议用在同一标签
-
在Vue2中,
v-for优先级是高于v-if的 ,当 v-for 和v-if同时存在,优先执行v-for,再执行v-if,会增加无用操作demo:
下面的代码会先把7个元素都遍历出来,然后再一个个判断是否为3,并把3给==销毁==,这样的坏处就是,渲染了无用的3节点,增加无用的dom操作
<div v-for="item in [1, 2, 3, 4, 5, 6, 7]" v-if="item !== 3"> {{item}}</div> -
解决方案:
-
computed过滤 -
template嵌套
-
12、Vue响应式数据理解
Vue响应式数据核心是运用了
Objec.defineProperty()当把js对象传入Vue实例的data,Vue会遍历这个对象所有
property,Objec.defineProperty()把所有的property都转为getter / setter, 使property在被访问或修改的时候通知变更,然后view更新
13、不需要响应式的数据应该怎么处理?
-
将数据定义在data return 之前即:
data () {
this.list1 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list2 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list3 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list4 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list5 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
return {} } -
Object.freeze()
用于冻结某对象,冻结之后将无法再改变对象属性
data () {
return {
list1: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list2: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list3: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list4: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list5: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
}
}
14、双向数据绑定 & 单向数据流
- 双向数据绑定:
1、Vue 提供了
v-model指令,它能轻松实现表单输入和应用状态之间的双向绑定2、
v-model指令在表单<input>、<textarea>及<select>元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素3、但
v-model本质上不过是语法糖。它负责监听用户的输入事件(@input)以更新数据(@change),并对一些极端场景进行一些特殊处理。
- 单向数据流:
1、Vue父子组件之间数据传递,遵循单向数据流的,父组件可以向子组件传递props,但是子组件不能修改父组件传递来的props,子组件只能通过事件通知父组件进行数据更改
- 小结:
Vue双向数据绑定和单向数据流并不冲突,本质上Vue依然是单向数据流,v-model只是对表单事件做了一层封装用于更好的处理表单数据
15、插槽
用于Vue内容分发,将 <slot> 元素作为承载分发内容的出口。
1. 语法:
<slot name="xxxx"></slot>2. 使用:
假如内容要插入的位置如下
<p> // 内容插入这里👉<slot name="slot-test">我是插槽默认值,在没有传递数据的时候显示</slot>👈 </p>2.6.0版本前
<span slot="slot-test"> 我是要插入的内容 </span>2.6.0版本以后( Vue 提供了
v-slot标签)<template v-slot:slot-test> <span> 我是要插入的内容 </span> </template>
16、Provide-inject
provide 选项允许我们指定我们想要提供给后代组件的数据/方法
然后在任何后代组件里,我们都可以使用 inject 选项来接收指定的我们想要添加在这个实例上的 property
Demo:
#parent
provide: function () {
return {
getMap: this.getMap, //这样写是非响应式,provide数据变化,inject不会更新数据
responsive_getMap: this, //响应式数据需要把整个this结构传递给inject
}
}
#children
inject: ['getMap']
# or
inject: {
getMap1: {
from: 'getMap1',
default: () => {}
},
responsive_getMap1: {
from: 'responsive_getMap1',
default: () => {}
}
}
#####17、 父子组件生命周期顺序
子组件创建时间: 父组件beforeMounted 和 Mounted之间
18、对象新属性无法更新视图,删除属性无法更新视图,为什么?怎么办?
原因:
Object.defineProperty没有对对象的新属性进行属性劫持方案:
对象新属性无法更新视图:使用
Vue.$set(obj, key, value),组件中this.$set(obj, key, value)删除属性无法更新视图:使用
Vue.$delete(obj, key),组件中this.$delete(obj, key)
19、为什么只对对象 ==数据劫持==,而要对数组进行方法重写?
-
因为对象最多也就几十个属性,拦截起来数量不多,但是数组可能会有几百几千项,拦截起来非常耗性能,所以直接重写数组原型上的方法,是比较节省性能的方案
-
修改数组数据
arr[index] = xxx无法更新视图解决方案:-
使用数组的splice方法,
arr.splice(index, 1, item) -
使用
Vue.$set(arr, index, value)
-
20、props怎么自定义验证
props: {
num: {
default: 1,
validator:
function (value) {
// 返回值为true则验证不通过,报错
return [1, 2, 3, 4, 5].indexOf(value) !== -1
}
}
}
21、watch的immediate属性有什么用?
使用immediate为true时,会初始执行一次
watch: {
searchInputValue:{
handler: 'getList',
immediate: true
}
}
22、computed如何实现传参?
// html
<div>{{ total(3) }}</div>
// js
computed: {
total() {
return function(n) {
return n * this.num
}
},
}
23、class 与 style 如何动态绑定?
-
动态class对象:
<div :class="{ 'is-active': true, 'red': isRed }"></div> -
动态class数组:
<div :class="['is-active', isRed ? 'red' : '' ]"></div> -
动态style对象:
<div :style="{ color: textColor, fontSize: '18px' }"></div> -
动态style数组:
<div :style="[{ color: textColor, fontSize: '18px' }, { fontWeight: '300' }]"></div>
26、.sync用法
parent 👇
<dialog :visible.sync="dialogVisible" />
child 👇
<el-dialog title="xxxx" :visible="visible" @close="close" />
close() {
this.$emit("update:visible", false);
},
27、过滤器(filter)
自定义过滤器,常用于一些常见的文本格式化
规则:变量名 + “ | ” + 过滤器名
<!-- 在双花括号中 -->
<div>{{ message | capitalize }}</div>
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | capitalize"></div>
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
28、Vue的虚拟DOM原理?
28-1、什么是虚拟dom?
虚拟DOM简单来说就是一个js对象构建的树,用对象的属性描述dom节点,通过一些操作最后渲染为真正的DOM节点
28-2、虚拟DOM和真实DOM怎么映射的?
-
js
<ul id='list'> <li class='item'>Item 1</li> <li class='item'>Item 2</li> <li class='item'>Item 3</li> </ul> -
Virtual Dom
var element = { tagName:'ul', props:{ id:'list'}, children:[ {tagName:'li',props:{class:'item'},children:['Item1']}, {tagName:'li',props:{class:'item'},children:['Item2']}, {tagName:'li',props:{class:'item'},children:['Item3']}, ] }
28-3、为什么要使用虚拟DOM
-
操作原生DOM慢,且消耗性能,js运行效率高
-
Virtual DOM的优势不在于单次的操作,而是在大量、频繁的数据更新下,能够对视图进行合理、高效的更新。
29、Vue Diff算法
-
什么是diff算法
在页发生大量重绘及回流的时候用于计算DOM节点变化,最后只修改发生变化的DOM节点,而不用对整DOM进行更新
-
回流:浏览器重新渲染部分或全部文档的过程
-
重绘:当页面中元素
样式
的改变并不影响它在文档流中的位置时(例如:
color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
-
-
原理
虚拟DOM会先生成一棵virtual DOM,当virtual DOM某个节点发生改变的时候会生成新的Vnode,然后新旧Vnode进行对比,发现有修改的地方再去修改真实DOM
30、element自定义表单校验
{ validator: (rule, value, callback) => { if (!Boolean(value)) { callback(new Error("请输入用户评分阈值")); } if (value > 100) { callback(new Error("用户评分阈值不能大于100")); } callback(); }, trigger: "blur",},
31、NextTick用处
-
Vue 在更新 DOM 时是异步执行的 , 只要侦听到数据变化, Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更
-
同一事件循环内
多次修改,会统一进行一次视图更新(☝☝☝上句话的通俗解释) -
使用场景:
数据更新,视图还未更新,我们需要拿到最新视图数据的时候使用
demo:
<div ref="testDiv">{{name}}</div>name: '小林'this.name = '林三心'console.log(this.$refs.testDiv.innerHTML) // 小林this.$nextTick(() => { console.log(this.$refs.testDiv.innerHTML) // 林三心})
32、生命周期
33、Vue能否在==data==里面直接使用props传过来的值,为什么?
可以直接使用,因为在Vue源码中使用
initState( )函数初始化Vue组件实例状态,其中初始化顺序依次为:props
—>
methods
—>
data
—>
computed
—>
watch
export function initState(vm) {
// 获取传入的数据对象
const opts = vm.$options;
if (opts.props) { initProps(vm); }
if (opts.methods) { initMethod(vm); }
if (opts.data) { // 初始化data initData(vm); }
if (opts.computed) { initComputed(vm); }
if (opts.watch) { initWatch(vm); }
}
34、为什么Vue的data是个函数并且返回一个对象呢?
当data是个函数的时候,组件每次调用data中的数据,data执行都会返回一个新的对象,防止多处调用造成数据污染
35、Vue中为什么可以直接使用this.name='测试'直接访问或修改data中的数据
Vue实例中初始化
data数据的时候,使用Object.defineProperty 对数据做了一层代理,==将数据都挂载在Vue实例上==,最后结果形成如this.name==>this._data .name,我们可以使用 this.a 来访问 this._data.a
// 数据代理
function proxy(object, sourceKey, key) {
Object.defineProperty(object, key, {
get() {
return object[sourceKey][key];
},
set(newValue) {
object[sourceKey][key] = newValue;
},
});
}
36、Vue+elememt table表单校验
<el-form ref="work_plan_form" :model="dataInfo" :rules="rules"> <el-table :data="dataInfo.workPlan" style="width: 100%"> <el-table-column label="序号" type="index" align="center" /> <el-table-column label="班次" align="center" prop="name"> <template slot-scope="{ row, $index }"> <el-form-item :prop="`workPlan.${$index}.name`" :rules="rules.name"> <el-input v-model="row.name" placeholder="" maxlength="20"></el-input> </el-form-item> </template> </el-table-column> <el-table-column label="服务时间" align="center" prop="serviceTime"> <template slot-scope="{ row, $index }"> <el-form-item :prop="`workPlan.${$index}.serviceTime`" :rules="rules.serviceTime" > <el-time-picker @change="(val) => serviceTimeChange(val, row)" style="width: 400px" value-format="HH:mm" is-range v-model="row.serviceTime" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" placeholder="选择时间范围" /> </el-form-item> </template> </el-table-column> <el-table-column label="顾问" align="center" prop="adviser"> <template slot-scope="{ row, $index }"> <el-form-item :prop="`workPlan.${$index}.adviser`" :rules="rules.adviser"> <el-select v-model="row.adviser"> <el-option v-for="item in []" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" /> </el-select> </el-form-item> </template> </el-table-column> </el-table> </el-form>