1.vue的原理?
关键词: 虚拟DOM树
+访问器属性
- 解释一下:响应式原理?
当你把一个普通的 JavaScript 对象传入 Vue 实例作为
data
选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty把这些 property 全部转为 getter/setter这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更,每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
- vue为什么不支持IE8及更低版本?
Object.defineProperty` 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
2. vue有哪些缺点
- Vue 不能检测数组和对象的变化
3.为什么vue不能检测对象的变化
对于对象, Vue 无法检测 property 的添加或移除,由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的.
- 追问:那如何解决上述问题?
使用this.
$set
(this.someObject,'b',2) 添加新的属性
使用this.$delete
(this.someObject,'b') 删除旧属性
4.讲一下 $set 的实现原理
1、如果目标是数组,使用 vue 实现的变异方法 splice 实现响应式
2、如果目标是对象,判断属性存在,即为响应式,直接赋值
3、如果 target 本身就不是响应式,直接赋值
4、如果属性不是响应式,则调用 defineReactive 方法进行响应式处理
核心代码如下
export function set(target: Array | Object, key: any, val: any): any {
// target 为数组
if (Array.isArray(target) && isValidArrayIndex(key)) {
// 修改数组的长度, 避免索引>数组长度导致splice()执行有误
target.length = Math.max(target.length, key);
// 利用数组的splice变异方法触发响应式
target.splice(key, 1, val);
return val;
}
// target为对象, key在target或者target.prototype上 且必须不能在 Object.prototype 上,直接赋值
if (key in target && !(key in Object.prototype)) {
target[key] = val;
return val;
}
// 以上都不成立, 即开始给target创建一个全新的属性
// 获取Observer实例
const ob = (target: any).__ob__;
// target 本身就不是响应式数据, 直接赋值
if (!ob) {
target[key] = val;
return val;
}
// 进行响应式处理
defineReactive(ob.value, key, val);
ob.dep.notify();
return val;
}
5.new Vue()实例中,data 可以直接是一个对象,为什么在 vue 组件中,data 必须是一个函数呢?
关键词:复用
+污染
+ 函数返回
+ 数据拷贝
因为组件是可以复用的,JS 里对象是引用关系,如果组件 data 是一个对象,那么子组件中的 data 属性值会互相污染,产生副作用。所以一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。new Vue 的实例是不会被复用的,因此不存在以上问题。
6.computed 和 watch 有什么区别?
computed 计算属性 :
依赖其它属性值,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值,如果和上次计算结果不一致,重新渲染页面。
watch 侦听器 : 更多的是「观察」的作用,无缓存性,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作。
追问:computed 和 watch 应用场景?
关键词 computed
+缓存
computed :当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算。
watch: 当我们需要在数据变化时执行的操作时使用(如调用其它函数)
追问 :能使用箭头函数定义computed和watch吗?
不应该使用箭头函数来定义 watcher 函数,理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,为undefined
7.MVC和MVVM的原理
-
MVC
视图(View):用户界面。
控制器(Controller):业务逻辑
模型(Model):数据保存
实现流程
1.View 传送指令到 Controller
2.Controller 完成业务逻辑后,要求 Model 改变状态
3.Model 将新的数据发送到 View,用户得到反馈
- MVVM
视图(View):用户界面。
视图模型(VM):双向数据绑定
模型(Model):数据+业务
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互. Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
8.vue数据绑定是双向还是单向的
Vue 在不同组件间强制使用单向数据流。这使应用中的数据流更加清晰易懂。
9.v-model双向绑定的原理?
v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据.
原理如下:
Object.defineproperty()重新定义(set方法)对象设置属性值和(get方法)获取属性值的操纵来实现的.
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
9.全局导航钩子函数应用场景?
vue router.beforeEach(全局前置守卫)router.beforeEach 是页面加载之前(before each)意思是在 每次每一个路由改变的时候都得执行一遍.
vue router.afterEach(全局后置守卫),相反router.afterEach是页面加载之后.
应用场景:
- 可进行一些页面跳转前处理,例如判断需要登录的页面进行拦截,做登录跳转!
2.进入页面登录判断、管理员权限判断、浏览器判断
10 .v-if和v-for在同一个标签中的执行顺序?
v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度注意v-for 遍历避免同时使用 v-if
如果需要使用判断,建议使用计算属性
<ul> <li v-for="user in activeUsers" :key="user.id"> {{ user.name }} </li></ul>
computed: { activeUsers: function () { return this.users.filter(function (user) { return user.isActive }) }}
10.路由独享的守卫(路由内钩子)
路由独享的守卫(路由内钩子)你可以在路由配置上直接定义 beforeEnter 守卫:
const router = new VueRouter({ routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// 处理
...
next()
}
} ]
11.vue-loader是什么?它有什么作用?
解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代 码 style、以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理。
12.vue中怎么重置data?
this .$options.data可以获取到组件初始化状态下的datathis.$data获取当前状态下的data// 将数据拷贝到this.$data中即可Object.assign(this.$data, this.$options.data())
13.在vue项目中如果methods的方法用箭头函数定义结果会怎么样?
因为箭头函数默绑定父级作用域的上下文,所以不会绑定vue实例, 在严格模式下this是undefined,在非严格模式下指向window
14.vue怎么实现强制刷新组件?
1.调用强制刷新方法 this.$forceUpdate()
- 给模板上绑定key值,通过修改key值,实现组件刷新<SomeComponent :key="theKey"/>//选项里绑定datadata(){ return{ theKey:0 }}//刷新key达到刷新组件的目的theKey++;
15.如何在子组件中访问父组件的实例?
通过this.parent.event来调用父组件的方法
2:在子组件里用$emit向父组件触发一个事件,父组件监听这个事件
3:父组件把方法传入子组件中,在子组件里直接调用这个方法父组件如何调用子组件的方法?给子组件设置属性ref
<子组件 ref="name" />可以在子组件中加上ref,然后通过this.$refs.ref.method调用
16.vue组件里写的原生addEventListeners监听事件,要手动去销毁吗?为什么?
需要, Vue不会主动移除监听事件, 多次进入组件,事件会绑定多次,另一方面是函数没释放会内存溢出.
17.组件中写name选项有什么作用?
a.项目使用keep-alive时,可搭配组件name进行缓存过滤b.DOM做递归组件时需要调用自身name
c.vue-devtools调试工具里显示的组见名称是由vue中组件name决定的
18.<template></template>
有什么用?
当做一个不可见的包裹元素,减少不必要的DOM元素,整个结构会更加清晰。使用场景主要用于分组的条件判断和列表渲染。结合v-for、v-if等一起使用,插槽时使用
19 .vue组件之间的通信都有哪些?
父子组件传值
- 通过props属性传值
- 通过on传值
- ( children ) / $refs
兄弟组件传值
1.Vuex
2.Bus
跨级组件传值
- provide/inject
- listeners
20.route和router有什么区别?
route:代表当前路由信息对象,可以获取到当前路由的信息参数router:代表路由实例的对象,包含了路由的跳转方法,钩子函数等
21.怎样动态加载路由?
通过router.addRoutes方法可以动态加载路由.
let router=new VueRouter({
routes:[
{path:'/product',component:a,name:'product'}
]
});
router.addRoutes([
{path:'/user',component:c,name:'user'},
{path:'/address',component:address,name:'address'}
]);
22.说说active-class是哪个组件的属性?
active-class是vue-router模块的router-link组件中的属性,用来设置选中连接的样式.
23.为什么vue使用异步更新组件?
收集当前的改动一次性批量更新,为了节省diff开销.
24.怎么缓存当前的组件?缓存后怎么更新?
1.通过keep-alive组件缓存需要缓存的组件
<keep-alive includes="组件1name,组件2name">
<router-view>
</keep-alive>
2.当组件激活后,会触发钩子函数actived,在这个钩子函数中,做数据更新.
25.vue怎么获取DOM节点?
为组件定义ref属性<input ref="myInput">通过this.$refs.myInput 就可以获取dom节点.
26.vuex中actions和mutations有什么区别?
1.mutations可以直接修改state,但只能包含同步操作,同时,只能通过提交commit调用.
2.actions可以包含异步操作,通过store.dispatch触发,不能直接修改数据,需要调用commit去修改数据.
27. 怎么监听vuex数据的变化?
通过watch监听数据的变化
watch:{
'$store.state.test':function(value){
console.log('数据修改了',value)
}}
28.开启vuex中的严格模式有什么好处?
主要用户防止不合理的改变状态值如:this.$.store.state.list = [],这样就会抛出异常
A.在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
B. 不要在发布环境下启用严格模式!严格模式会深度监测状态树来检测不合规的状态变更——请确保在发布环境下关闭严格模式,以避免性能损失。
如何使用?
const store = new Vuex.Store({
// 让构建工具自动帮我们处理
strict: process.env.NODE_ENV !== 'production'
})
30.你了解双向绑定的计算属性的应用场景吗?
<input type="text" v-model="username">
如果我们想要监听用户输入变化,我们首先会想到下面的方法
<input type="text" v-model="username" @input="onChange">
其实我们可以使用双向绑定的计算属性来实现
data() {
return { _username:'' };
}, computed:{
username:{
get(){
return this._username
},
set(value){ // 监听数据变化
console.log('监听数据变化',value)
this._username = value }
}
}
当我们使用了Vuex时,并且开启了严格模式,那么我们就不能直接绑定状态值了, 在用户输入时,v-model 会试图直接修改状态name的值,这样会抛出异常<input v-model="$store.state.name">这个时候我们需要使用双向绑定的计算属性来解决这个问题
<input v-model="name">
computed: {
name: {
get () {
return this.$store.state.name
},
set (value) {
this.$store.commit('updateName', value)
}
}}
30.vue中的指令v-on如何绑定多个属性?
v-on={ 事件名:绑定的自定义回调函数}
<input type="text" v-on="{input:onInput,focus:onFocus}"/>
31.vue中使用delete删除对象的属性,页面会更新吗?
delete this.list[1]
页面不会更新, Vue不能检测到 property 被删除那么如何在删除元素或者对象属性时,可以触发更新视图?this.$delete(this.list,1)
32.watch怎么深度监听对象变化?
data() {
return {
data:{},
user:{
info:{ name:123 }
}
};
}
比如我们要对user.info 属性进行监听,如果info属性有任何更改触发通知
watch:{ 'user.info':{
handler(value){
console.log("数据变化",value)
}
}
}
此时我们调用
this.user.info.name = "8888888"handle方法不会被触发.这个user.info是一个对象
Vue只响应对象的地址变化进行响应.
如果我们需要让Vue对整个info里面的属性变化,进行监听,
就需要开启深度监听属性deep:true
watch:{
'user.info':{
handler(value){
console.log("数据变化",value)
},
deep:true
}
}
33 .vue组件会在什么时候下被销毁?
1.页面关闭、
2.路由跳转、
3.v-if为false
4.改变key值
33.怎么使css样式只在当前组件中生效
给style标签添加scoped属性, 通过该属性,可以使得组件之间的样式不互相污染<style scoped> </style>
原理vue中的scoped属性的效果主要通过PostCSS转译实现, PostCSS给一个组件中的所有dom添加了一个独一无二的动态属性,然后,给CSS选择器额外添加一个对应的属性选择器来选择该组件中dom.
<div adfs-888-123213 ></div>
vue
vuex
vue-reouter
axios
https://developer.mozilla.org/zh-CN/docs/Web/HTTP
微信小程序
支付宝小程序
can I use
实战经验
安全
ES6教程
javascript