1. 数据双向绑定原理
vue的双向绑定是由数据劫持结合发布者-订阅者模式实现的,那么什么是数据劫持?就是通过Object.defineProperty()来劫持对象属性的setter和getter操作,在数据变动时做你想要做的事情。
数据劫持set和get函数起到什么作用?
回顾一下Object.defineProperty:
- 语法:Object.defineProperty(obj, prop, descriptor)
- 参数:
obj:目标对象
prop:需要定义的属性或方法的名称
descriptor:目标属性所拥有的特性 - 可供定义的特性列表
value:属性的值
writable:如果为false,属性的值就不能被重写。
get:一旦目标属性被访问就会调用此方法,并将此方法的运算结果返回用户。
set:一旦目标属性被赋值,就会调回此方法。
configurable:如果为false,则任何尝试删除目标属性或修改属性以下特性(writable, configurable, enumerable)的行为将被无效化。
enumerable:是否能在for…in循环中遍历出来或在Object.keys中列举出来。
拓展:js中遍历一个对象的属性的方法
- Object.keys() 仅仅返回自身的可枚举属性,不包括继承来的,更不包括Symbol属性
- Object.getOwnPropertyNames() 返回自身的可枚举和不可枚举属性。但是不包括Symbol属性
- Object.getOwnPropertySymbols() 返回自身的Symol属性
- for…in 可以遍历对象的自身的和继承的可枚举属性,不包含Symbol属性
- Reflect.ownkeys() 返回对象自身的所有属性,不管是否可枚举,也不管是否是Symbol。注意不包括继承的属性
2. v-for 和 v-if 谁先执行?
当它们处于同一节点,v-for的优先级比v-if更高,这意味着 v-if将分别重复运行于每个 v-for循环中。
Vue 会先执行 v-for 得到 item 然后执行 v-if 判断是否展示。
官网并不推荐同一节点使用,原因是会影响性能增加渲染时长,我们可以在渲染之前把数据处理好。
3. v-html会导致哪些问题?
1.可能会导致 xss 攻击。用v-html一定要保证你的内容是可以依赖的,不要用在用户提交的内容上
// 因为用户输入的信息不可信,这样输入什么就会放入什么,v-html就相当于一个innerHTML
2.v-html 会替换掉标签内部的子元素
4. vue中的 watch、computed 和 methods之间的差别以及应用场景:
computed 和 watch,一个是计算,一个是观察,在语义上是有区别的。
计算是通过变量计算来得出数据。而观察是观察一个特定的值,根据被观察者的变动进行相应的变化,在特定的场景下不能相互混用,所以还是需要注意api运用的合理性和语义性。
computer
当页面中有某些数据依赖其他数据进行变动的时候,可以使用计算属性。
需要注意的是,就算在data中没有直接声明出要计算的变量,也可以直接在computed中写入。
computed比较适合对多个变量或者对象进行处理后返回一个结果值,也就是多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化。(举例:购物车里面的商品列表和总金额之间的关系,只要商品列表里面的商品数量发生变化,或减少或增多或删除商品,总金额都应该发生变化。这里的这个总金额使用computed属性来进行计算是最好的选择。)
计算属性默认只有getter,可以在需要的时候自己设定setter:
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
适用场景:
watch
watch和computed很相似,watch用于观察和监听页面上的vue实例,当然在大部分情况下我们都会使用computed,但如果要在数据变化的同时进行异步操作或者是比较大的开销,那么watch为最佳选择。
watch一般用于监控路由、input输入框的值特殊处理等等,它比较适合的场景是一个数据影响多个数据。
watch为一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。直接引用文档例子:
var vm = new Vue({
el: '#app',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
如果在data中没有相应的属性的话,是不能watch的,这点和computed不一样。
适用场景:
methods方法
跟前面的都不一样,我们通常在这里面写入方法,只要调用就会重新执行一次,相应的有一些触发条件,在某些时候methods和computed看不出来具体的差别,但是一旦在运算量比较复杂的页面中,就会体现出不一样。
需要注意的是,computed是具有缓存的,这就意味着只要计算属性的依赖没有进行相应的数据更新,那么computed会直接从缓存中获取值,多次访问都会返回之前的计算结果。
5. Vue-router相关:
5.1 vue-router的几种模式?JS是如何监听HistoryRouter的变化的?
通过浏览器的地址栏来改变切换页面,前端实现主要有两种方式:
1. 通过hash改变,利用window.onhashchange 监听。
2. 通过history的改变,进行js操作加载页面。然而history并不像hash那样简单, 因为history的改变,除了浏览器的几个前进后退(使用 history.back(),history.forward() 和 history.go() 方法来完成在用户历史记录中向后和向前的跳转)等操作会主动触发popstate 事件,pushState、replaceState 并不会触发popstate事件,要解决history监听的问题,方法是:
首先完成一个订阅-发布模式,然后重写history.pushState、history.replaceState 并添加消息通知,这样一来只要history的无法实现监听函数就被我们加上了事件通知,只不过这里用的不是浏览器原生事件,而是通过我们创建的event-bus 来实现通知,然后触发事件订阅函数的执行。
5.2 HashRouter 和 HistoryRouter:
vue-router是Vue官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。 vue-router 默认 hash 模式,还有一种是history模式。
原理:
-
hash路由:hash模式的工作原理是hashchange事件,可以在window监听hash的变化。我们在 url后面随便添加一个#xx触发这个事件。vue-router默认的是hash模式—使用URL的hash来模拟一个完整的URL,于是当URL改变的时候页面不会重新加载,也就是单页应用了,当#后面的hash发生变化,不会导致浏览器向服务器发出请求,浏览器不发出请求就不会刷新页面,并且会触发hashChange 事件,通过监听hash值的变化来实现更新页面部分内容的操作。
对于hash模式会创建hashHistory对象,在访问不同的路由的时候,会发生两件事: HashHistory.push()将新的路由添加到浏览器访问历史的栈顶,和HasHistory.replace()替换到当前栈顶的路由。
-
history路由:
主要使用HTML5的pushState()和replaceState()这两个api结合window.popstate事件(监听浏览器前进后退)实现的。pushState()可以改变url地址且不会发送请求,replaceState()可以读取历史记录栈,还可以对浏览器记录进行修改。
区别:
-
hash模式较丑,history模式较优雅;
-
pushState设置的新URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分,故只可设置与当前同文档的URL
-
pushState设置的新URL可以与当前URL一模一样,这样也会把记录添加到栈中;而hash设置的新值必须与原来不一样才会触发记录添加到栈中;
-
pushState通过stateObject可以添加任意类型的数据到记录中,而hash只可添加短字符串;
-
pushState可额外设置title属性供后续使用;
-
hash兼容IE8以上,history兼容IE10以上;
-
hist