目录
- 什么是DOM
- DOM渲染流程
- vue打包后,static和assets的区别
- vue指令有哪些
- vue自定义指令
- vue注册全局组件
- Vue的修饰符有哪些?
- v-if和v-show的区别
- v-if和v-for为什么不能同时使用
- 说说key的作用
- v-for为什么要用key
- 组件传值的方法
- vue子组件和父组件创建和挂载的顺序
- vue中的data为什么是函数而不是对象?
- watch和computed的区别
- computed特性
- computed缓存原理
- keep-alive
- 什么是插槽slot
- vue有哪些修饰符
- vue2为什么监听不到数组
- vue生命周期
- vue中created和mounted的区别
- vue数据双向绑定原理
- 什么是MVVM
- 怎么理解Vue单向数据流
- 对vue响应式的理解
- 对虚拟dom的理解
- 虚拟DOM的原理
- 对diff算法的理解
- nextTick的使用和原理
- 从template到render发生了什么
- Vue实例挂载过程发生了什么
- vue优化方法有哪些
- 为什么选择使用vue
- vue的缺点
- SPA单页面应用
- intercepetor拦截
- mixin是什么
- mixin和vuex的区别
什么是DOM
当网页被加载时,浏览器就会创建页面的文档对象模型(document object model)。dom定义了访问HTML文档的标准。dom是中立于平台和语言的接口,允许程序和脚本动态的访问更新文档内容结构样式
DOM渲染流程
1、浏览器解析HTML代码,创建一个DOM树
2、浏览器解析css代码,计算出样式,构建一个渲染树
3、浏览器根据渲染树绘制页面
vue打包后,static和assets的区别
相同点:都是放静态资源的
不同点:项目打包时assets的资源也会打包;static不需要打包直接进入打包好的目录,占用空间较大
vue指令有哪些
v-model v-for v-if v-else v-show v-html
vue自定义指令
Vue.directive('focus', {
inserted: function (el) {
el.focus()
},
})
bind:只调用一次,指令第一次绑定到元素时调用
inserted:被绑定元素插入父节点时调用
update:所在组件的vnode更新时调用
componentUpdated:所在组件的vnode及子组件的vnode全部更新后调用
unbind:只调用一次,指令和元素解绑时调用
vue注册全局组件
components文件下建立公共组件
<template>
<el-button :disabled="disabled" :type="type" @click.stop="clickFunction">
<slot></slot>
</el-button>
</template>
<script>
export default {
name: "Button",
props: {
type: { // primary denger
type: String,
default: "primary",
},
disabled: {
type: Boolean,
default: false,
},
},
};
</script>
components文件下建立index.js
// 给自定义组件添加install方法
const components = require.context('./', false, /\.vue$/) // require.context获取指定目录下符合条件的文件,这里获取所有components目录下的组件
let newComponents = []
components.keys().map(item => {
const componentConfig = components(item).default
componentConfig.install = function (Vue) {
Vue.component(componentConfig.name, componentConfig);
};
newComponents.push(componentConfig)
})
export default newComponents;
在main.js中引用
// 注册全局组件
import components from '../src/components/index'
components.map(component => {
Vue.use(component)
})
// 使用
<Button @click="btn1">Button</Button>
<Button type="denger" @click="btn2">denger</Button>
效果
Vue的修饰符有哪些?
.tirm(首尾去空格) .number(先输入数字就限制输入只能是数字) .lazy(光标离开后再更新input数据)
v-if和v-show的区别
v-if是通过添加删除DOM元素控制显示隐藏,频繁操作会消耗性能,初次加载使用v-if
v-show是通过设置display的值控制显示隐藏,只会编译一次,频繁切换使用v-show
v-if和v-for为什么不能同时使用
v-for的优先级高于v-if,每次渲染都要先循环再进行条件判断,同时使用会导致性能浪费
说说key的作用
key主要作用是更高效的更新虚拟dom
key是vue在patch过程中判断两个节点是否是相同节点的必要条件。渲染一组列表时,key往往是唯一标识。如果不定义key的话,vue就会认为比较的两个节点是同一个,哪怕实际上不是,这导致了频繁更新元素,影响性能。如果定义key且两个节点的key相同,那么两个节点为相同节点的可能性就很大,在patch过程中就可以直接利用之前的节点,不必删除或新建节点
v-for为什么要用key
key是vnode唯一的id,也是diff的优化策略。可以根据key更快更准确的找到对应的vnode节点
未用key:vue采用就地复用原则,最小化element的移动,并且会尝试尽最大程度在同适当的地方对相同类型的element,做patch或者reuse。
使用key:vue根据key的顺序记录element,曾经拥有了key的element如果不再出现的话,会被直接remove或者destoryed
组件传值的方法
父组件向子组件传值用props
子组件向父组件传值用$emit
兄弟组件传值:
// 创建一个事件总线 新建一个bus.js文件
import Vue from 'vue';
export default new Vue;
// 需要传值的组件使用$emit传递参数
import bus from '@/common/bus';
bus.$emit(‘transfer’,this.msg)
// 在接收数据的组件中使用$on监听自定义事件
import bus from '@/common/bus';
bus.$on(‘transfer’,(data)=>{
// data就是兄弟组件传过来的msg
this.str = data
})
祖孙传值:
// 祖先使用provide传值
provide() {
return {
grandPaMsg: "我是祖先数据",
};
},
// 子孙使用inject接收值
<template>
<div>子孙组件:{{ grandPaMsg }}</div>
</template>
<script>
export default {
inject: ["grandPaMsg"],
};
</script>
vuex mixin 浏览器存储等
vue子组件和父组件创建和挂载的顺序
创建过程自上而下,挂载过程自下而上
parent created => child created => child mounted => parent mounted
vue中的data为什么是函数而不是对象?
函数有自己的作用域,组件被复用时,每个组件都有自己的数据,这样组件之间才不会相互干扰
watch和computed的区别
watch特点:侦测变化,执行回调
watch监听的数据必须是在data里声明或从父组件传过来的数据,当监听的数据发生改变时会触发,无缓存支持异步
computed特点:有响应式的返回值
computed监听的数据直接定义在computed里面,当传入的数据发生改变就会触发,有缓存不支持异步
//watch场景:一个数据影响多个数据
watch:{
newObj:{
handle(newV,oldV){}
deep:true
}
}
//computed场景:一个数据受多个数据影响
computed:{
newStr(){
return this.str.toUpperCase()
}
}
computed特性
1、computed是惰性的。computed依赖的数据发生变化时,computed不会立即计算,要等到求值时才会重新计算
2、computed是有缓存的。computed依赖的数据没有变化,及时重新对computed求值,也不会重新计算
computed缓存原理
当computed依赖的数据发生变化时才会清空缓存重新计算
computed的缓存机制是通过dirty属性控制的,当依赖数据变化时dirty就会设置为true,才会重新计算结果,计算后dirty再次设为false
keep-alive
作用:缓存组件,提升性能;
添加了activated和deactivated生命周期,首次进入keep-alive页面触发了beforeCreate、created、beforeMount、mounted、activated,再次进入只触发activated;离开组件时触发了deactivated
// 只缓存组件名字为home的组件
<keep-alive include="home"></keep-alive>
// 除了组件名字为home的组件不缓存,其他都缓存
<keep-alive exclude="home"></keep-alive>
什么是插槽slot
默认插槽:把父组件的内容分发到子组件<slot></slot>
具名插槽:通过name属性将不同的内容分发到不同的位置
// 父组件
<Son>
<p slot='a'></template>
</Son>
// 子组件
<slot name='a'></slot>
作用域插槽:将子组件的数据反馈到父组件
// 父组件
<slot-child><template slot-scope='scope'>{{scope.str}}</template></slot-child>
// 子组件
<slot :str='我是子组件数据'></slot>
vue有哪些修饰符
.trim 首尾去空格
.number 先输入数字就限制只能输入数字
.lazy 光标离开后在更新input数据
vue2为什么监听不到数组
Vue中使用object.defineProperty监听数据,但数组长度不定且数据太多,出于性能考虑使用this.$set
vue生命周期
beforeCreate创建前,在数据观测和初始化事件还未开始时触发
created创建后,会完成数据观测属性和方法的运算
beforeMount挂载前,render函数被调用生成虚拟DOM
mounted挂载后,DOM树渲染到页面,页面可以进行DOM操作
beforeUpdate更新前,数据有更新时调用
updated更新后,调用时组件已更新
beforeDestroy销毁实例前调用,实例仍可用
destroyed实例销毁后调用
vue中created和mounted的区别
created在模板渲染前调用,数据初始化请求放在created里
mounted在模板渲染后调用,依赖DOM的请求放在mounted里
vue数据双向绑定原理
通过object.defineProperty劫持数据的改变,如果数据改变了(在set中赋值),触发update方法更新节点内容,从而实现数据双向绑定
什么是MVVM
MVVM是model view viewmodel的缩写,model代表data数据访问层,view代表视图,viewmodel是在视图和模型之间进行通信
优点:耦合度低,可重用性高
怎么理解Vue单向数据流
父组件向子组件传值,子组件不能直接修改父组件传过来的数据
如何修改:子组件使用$emit让父组件修改;子组件将传过来的数据重新赋值
对vue响应式的理解
1、数据响应式就是能够检测数据变化并对这种变化作出响应的机制
2、响应式过程:
数据劫持(侦测数据的变化)
依赖收集(收集视图依赖了哪些数据)
发布订阅模式(数据变化时,通知需要更新的视图,并进行更新)
3、vue 目前通过 Object.defineProperty 来实现数据响应式。
对虚拟dom的理解
虚拟dom本身是一个JavaScript对象,它通过不同的属性去描述一个视图结构
优点:减少直接操作dom的次数,提高程序性能;方便实现跨平台
虚拟DOM的原理
1、用JavaScript模拟并渲染DOM树
2、比较新老DOM树,得到差异对象
3、将差异对象渲染到DOM树上
对diff算法的理解
是什么:diff算法是虚拟dom技术的必然产物:diff就是对比新旧虚拟dom,将变化的地方更新到真实的dom上。
何时执行:组件数据发生变更时通知该组件执行渲染函数得到最新的虚拟dom,对比新旧虚拟dom找到变化的地方,将其转化为对应的dom操作
diff策略:深度优先、同层比较。
- 比较同层节点
- 没有相同节点就删除重新创建,
- 节点相同,双方都是文本则更新文本内容
- 节点相同,双方都是元素节点,则递归更新子元素,同时更新元素属性
- 更新子节点又分为以下几种情况:
新子节点为文本,老子节点为数组,则清空数组设置文本
新子节点为文本,老子节点为文本,则更新文本
新子节点为数组,老子节点为文本,则清空文本并创建数组中的子元素
新子节点为数组,老子节点为数组,则比较两组子节点,vue2使用双端算法从开头结尾找相同节点,如果找到就直接做比对
nextTick的使用和原理
作用:获取更新后的dom
原理:vue有异步更新机制,响应式数据发生变化vue不会立刻更新dom,开启一个队列存放组件的更新函数,同步代码执行完毕之后,使用异步的方式清空队列
场景:created中获取dom;响应式数据变化后获取更新后的dom
从template到render发生了什么
vue通过compiler编译器将template编译为js可执行的render函数
1、通过parser将template解析成AST抽象语法树
2、遍历AST标记所有的静态节点
3、将AST生成render函数
Vue实例挂载过程发生了什么
挂载过程指的是app.mount()过程
1、初始化。创建组件实例,初始化组件状态,创建各种响应式数据
2、建立更新机制。执行组件的更新函数,执行渲染函数得到虚拟DOM,通过patch将虚拟DOM转换成真实DOM;同时将我们的数据和组件的更新函数之间建立一个依赖关系,使得数据变化时执行对应的更新函数
vue优化方法有哪些
路由懒加载
keep-alive缓存组件
合理使用v-show和v-if
避免同时使用v-for和v-if
长列表性能优化
离开页面时,销毁定时器
图片懒加载<img v-lazy=''></img>
代码组件化
第三方插件按需加载
服务端渲染SSR
为什么选择使用vue
轻量级;简单易学;
组件化,方便管理维护;
响应式
vue的缺点
vue单页面应用不利于SEO优化
初次加载耗时多
SPA单页面应用
优点:前后端分离;减轻服务器压力
缺点:不利于SEO优化;首屏加载时间长
intercepetor拦截
请求拦截:
// 在请求头添加token
axios.interceptors.request.use((config)=>{})
响应拦截:
// 统一返回错误信息
axios.interceptors.response.use((res))=>{}
mixin是什么
用来分发vue组件可复用的组件
知识点:
混入对象的变量是不会共享的
同名钩子函数被调用,mixin比组件先执行
mixin的变量和组件的变量冲突,则以组件优先
mixin和vuex的区别
vuex是状态共享管理,vuex的变量和方法都是可以读取、更改并相互影响的;
mixin可以定义公共的变量和方法,引入组件后,各个变量都是相互独立的,值的修改不会相互影响