**一、**vue 2.6.11
vue****页面的生命周期?
总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
创建前/后: 在beforeCreate阶段,vue实例的挂载元素 e l 和 数 据 对 象 d a t a 都 为 u n d e f i n e d , 还 未 初 始 化 。 在 ∗ ∗ c r e a t e d ∗ ∗ 阶 段 , v u e 实 例 的 数 据 对 象 d a t a 有 了 , el和数据对象data都为undefined,还未初始化。在**created**阶段,vue实例的数据对象data有了, el和数据对象data都为undefined,还未初始化。在∗∗created∗∗阶段,vue实例的数据对象data有了,el还没有。
载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:当data变化时,会触发beforeUpdate和updated方法。
销毁前/后:beforeDestroy在执行destroyed方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一
vue****组件之间如何传值通信
父到子:
子组件在props中创建一个属性,用来接收父组件传过来的值;
在父组件中注册子组件;
在子组件标签中添加子组件props中创建的属性;
把需要传给子组件的值赋给该属性
子到父:
子组件中需要以某种方式(如点击事件)的方法来触发一个自定义的事件;
将需要传的值作为$emit的第二个参数,该值将作为实参传给响应事件的方法;
在父组件中注册子组件并在子组件标签上绑定自定义事件的监听。
平行组件:
e m i t 推 送 , emit推送, emit推送,on接收
Vue2.x****组件通信有哪些方式
- 父子组件通信: props 、 o n 、 on、 on、emit、 Ref 获取实例的方式调用组件的属性或者方法、(Provide、inject 官方不推荐使用,但是写组件库时很常用)
- 兄弟组件通信: EventBus 、Vuex
- 跨级组件通信:Vuex、 a t t r s 、 attrs、 attrs、listeners、Provide、(Provide、inject 官方不推荐使用,但是写组件库时很常用)
created和mounted****的区别?
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
DOM 渲染在哪个周期中就已经完成?
DOM 渲染在 mounted 中就已经完成了。
mvvm**,vue双向数据绑定的原理**
MVVM分为Model、View、ViewModel三者。
· Model 代表数据模型,数据和业务逻辑都在Model层中定义;
· View 代表UI视图,负责数据的展示;
· ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,主要是在监听器Observer和订阅者Watcher之间进行统一管理
MVC模式将软件分为下面三个部分 1.视图(View) :用户界面 2.控制器(Controller) :业务逻辑 3.模型(Model) :数据保存
vuex的state**、getter、mutation、action、module特性分别是什么?**
State: 保存着所有的全局变量
Getter: store中的计算属性,就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。 getters接收state作为其第一个参数,接受其他 getters 作为第二个参数,如不需要,第二个参数可以省略。
Mutation: 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation, mutation 必须是同步函数
Action: Action 可以包含任意异步操作, 在组件中使用 this.$store.dispatch(‘xxx’) 分发 action
Module: 可以写很多模块,Vuex 允许我们将 store 分割到模块(module)。每个模块拥有自己的 state、mutation、action、getters,最后都引入到一个文件。分散管理。
为什么mutation里面只能同步,不能异步?
就会方便追踪到state的变化,因为state里面的数据会改变 异步的话组件有可能会收不到 ,不能实时追踪
严格模式会报错
页面刷新后vuex的state数据丢失怎么解决?
将Vuex里的数据同步更新到localStorage里。
即:一改变vuex里的数据,便触发localStorage.setItem 方法
在 App.vue 的 created 钩子函数里写
//在页面加载时读取localStorage里的状态信息
localStorage.getItem(“userMsg”)&& this.$store.replaceState(JSON.parse(localStorage.getItem(“userMsg”)));
//在页面刷新时将vuex里的信息保存到localStorage里
window.addEventListener(“beforeunload”,()=>{
localStorage.setItem(“userMsg”,JSON.stringify(this.$store.state))
})
store****提供了哪些函数
提供getState( )方法获取state;
提供dispatch(action)方法更新state;
通过subscribe(listener)注册监听器;
通过subscribe(listener)返回的函数注销监听器
使用 mapState工具函数会将store中的state映射到局部计算属性中
mapGetter,mapMutation,mapAction会将store中各自的方法映射过来
vuex****是什么呢?哪些场景会用到?
vuex是一个专为vue.js应用程序开发的状态管理模式
我们大概可以理解为vuex是一个公共 状态库 , 你可以在所有的组件里面去使用,修改
场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物车
vuex为状态管理,它集中存储管理应用的所有组件的状态,可以理解成一个全局仓库
VueRouter是路由(spa)单页面应用的方式
使用vuex的优势是什么?有用过vuex吗?它主要解决的是什么问题?
Vuex的优势:
1.解决了非父子组件的消息传递(将数据存放在state中)
2.减少了AJAX请求次数,有些情景可以直接从内存中的state获取
主要解决的问题是:
用来管理全局的组件状态,比如有很多个组件都会修改同一个数据,同时这个数据又要在多个组件上同时显示,这个时候用 vuex 来统一管理这些组件的状态,会让逻辑更清晰,更可维护
vue和react****渲染有什么区别
vue—会跟踪每一个组件的依赖关系, 去重新渲染有依赖关系的组件,不是说重新渲染整个组件树。
react–如果某个组件状态发生变化,react会把这个组件还有这个组件的所有后代组件全部重新渲染,不过重新渲染并不是代表全部丢掉上一次的渲染结果,react通过diff去比较两次虚拟dom,比较之后再反映倒真实dom上,如果说组件树比较大,diff算法也是一比开销,react提供出来解决方案shouldComponentUpdate-----根据这个生命周期的返回结果来判断是不是需要执行后面的diff,update这些东西;
vue—Object.defineProperty get去收集依赖, 因此不会像react- 样去比较整颗组件树,去更加细粒度的去更新状态有变化的组件;
vue****中路由的模式如何选择,不同模式有什么区别?
Hash 模式
www.test.com/#/ 就是 Hash URL,当 # 后面的哈希值发生变化时,可以通过 hashchange 事件来监听到 URL 的变化,从而进行跳转页面,并且无论哈希值如何变化,服务端接收到的 URL 请求永远是 www.test.com。
window.addEventListener(‘hashchange’, () => {
// … 具体逻辑
})
Hash 模式相对来说更简单,并且兼容性也更好。
History 模式
History 模式是 HTML5 新推出的功能,主要使用 history.pushState 和 history.replaceState改变 URL。
通过 History 模式改变 URL 同样不会引起页面的刷新,只会更新浏览器的历史记录。
// 新增历史记录
history.pushState(stateObject, title, URL)
// 替换当前历史记录
history.replaceState(stateObject, title, URL)
当用户做出浏览器动作时,比如点击后退按钮时会触发 popState 事件
window.addEventListener(‘popstate’, e => {
// e.state 就是 pushState(stateObject) 中的 stateObject
console.log(e.state)
})
两种模式对比
· Hash 模式只可以更改 # 后面的内容,History 模式可以通过 API 设置任意的同源 URL
· History 模式可以通过 API 添加任意类型的数据到历史记录中,Hash 模式只能更改哈希值,也就是字符串
· Hash 模式无需后端配置,并且兼容性好。History 模式在用户手动输入地址或者刷新页面的时候会发起 URL 请求,后端需要配置 index.html 页面用于匹配不到静态资源的时候
r o u t e ∗ ∗ ∗ ∗ 和 ∗ ∗ ∗ ∗ route****和**** route∗∗∗∗和∗∗∗∗router****有什么区别,有什么关联关系
- $router 为 VueRouter 实例,想要导航到不同 URL,则使用 $router.push 方法。 $route 为当前 router 跳转对象里面可以获取 name 、 path 、 query 、 params 等。
插槽****slot
插槽(Slot)插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性,插槽就是Vue实现的一套内容分发的API
1.匿名插槽 :叫做默认插槽 就是没有名字
2.具名插槽:需要多个插槽时,可以利用元素的一个特殊的特性:name来定义具名插槽
3.作用域插槽:是父组件引用子组件中的数据,使用slot-scope 进行数据的传递,子组件中 将数据传递给父组件
v-for和v-if****的优先级
v-for的优先级高于v-if
watch
watch的原理 通过watch的方法,监听被改变的变量,然后再watch的那个变量命名的函数中去对我们要修改的值进行重新的赋值,或者是触发一次更新。 watch的执行类似于emit与on这种触发方式,通过vue的watch实例监听值来自动触发一个函数的执行。
· watch函数的参数中,第一个是改变之前的值,第二个是改变之后的值,这两个参数非常有用。
· 这里分别使用了 三种定义函数(或option)的方法。
· 如果要观察data下一个对象的属性,我们可以使用对象.属性的方式, 注意: 一定要要引号。
· 如果改变了一个对象的属性,就必须使用deep: true,否则检测不到变化。
watch和computed****差异
watch是进行数据监听,然后进行相应的操作,执行方法等conputed和methods的合体使用,比较耗性能,与vue性能优化相背而驰,尽量减少使用!computed是数据改变进行相应的数据变化,由老数据迸发新的数据(return返回),会利用缓存机制对 数据进行缓存 ,只有当 依赖数据变化的时候才会进行相应的变化
跨域
组件 data 为什么必须是函数
因为 JS 本身的特性带来的,如果 data 是一个对象,那么由于对象本身属于引用类型,当我们修改其中的一个属性时,会影响到所有 Vue 实例的数据。如果将 data 作为一个函数返回一个对象,那么每一个实例的 data 属性都是独立的,不会相互影响了。
$nextTick
$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM。
key
key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度
key具有唯一性,使用 key,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。 有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
带key就不会使用就地复用了,在sameNode函数 a.key===b.key对比中可以避免就地复用的情况。
vue中列表循环需加:key=“唯一标识” 唯一标识可以是item里面id index等,因为vue组件高度复用增加Key可以标识组件的唯一性,为了更好地区别各个组件 key的作用主要是为了高效的更新虚拟DOM
可以这样简单地理解,无:key属性时,状态默认绑定的是位置;有:key属性时,状态根据key的属性值绑定到了相应的数组元素。
若用数组索引index为key,当向数组中指定位置插入一个新元素后,对应着后面的虚拟DOM的key值全部更新了,这个时候还是会做不必要的更新,就像没有加KEY一样
为什么官网说的是就地更新的效率更高呢
key的作用就是更新组件时判断两个节点是否相同。相同就复用,不相同就删除旧的创建新的。在渲染简单的无状态组件时,如果不添加key组件默认都是就地复用,不会删除添加节点,只是改变列表项中的文本值,要知道节点操作是十分耗费性能的。而添加了key之后,当对比内容不一致时,就会认为是两个节点,会先删除掉旧节点,然后添加新节点。
vue****图片懒加载
vue-lazyload
vue****路由懒加载
方法一 resolve
这一种方法较常见。它主要是使用了resolve的异步机制,用require代替了import,实现按需加载,下面是代码示例:
import Vue from ‘vue’
import Router from ‘vue-router’
// import HelloWorld from ‘@/components/HelloWorld’
Vue.use(Router)
export default new Router({
routes: [
// {
// path: ‘/’,
// name: ‘HelloWorld’,
// component: HelloWorld
// }
{
path: ‘/’,
name: ‘HelloWorld’,
component: resolve => require([’@/components/HelloWorld’], resolve)
}
]
})
方法二 官网方法
vue-router在官网提供了一种方法,可以理解也是为通过Promise的resolve机制。因为Promise函数返回的Promise为resolve组件本身,而我们又可以使用import来导入组件。整合起来代码示例如下:
import Vue from ‘vue’
import Router from ‘vue-router’
// import HelloWorld from ‘@/components/HelloWorld’
Vue.use(Router)
export default new Router({
routes: [
// {
// path: ‘/’,
// name: ‘HelloWorld’,
// component: HelloWorld
// }
{
path: ‘/’,
name: ‘HelloWorld’,
component: () => import(’@/components/HelloWorld.vue’)
}
]
})
VUE****自定义指令
注册自定义指令分为全局注册与局部注册两种:
1.创建局部指令
var app = new Vue({
el: ‘#app’,
data: {
},
// 创建指令(可以多个)
directives: {
// 指令名称
dir1: {
inserted(el) {
// 指令中第一个参数是当前使用指令的DOM
console.log(el);
console.log(arguments);
// 对DOM进行操作
el.style.width = ‘200px’;
el.style.height = ‘200px’;
el.style.background = ‘#000’;
}
}
}
})
2.全局指令
Vue.directive(‘dir2’, {
inserted(el) {
console.log(el);
}
})
3.指令的使用