vue概略

vue

vue自定义事件

  1. vue自定义事件可以通过创建一个文件 event 里面new一个vue的实例 然后 通过两个随便是什么组件(兄弟 或者隔的比较远)的mounted中调用 一个调用on 然后传递一个函数 但是要在 beforeDestroy生命周期中销毁这个绑定 要不然容易造成内存泄漏 在另一个组件中的mothod的方法中使用emit调用

父子组件生命周期顺序

  1. cerated vue的实例已经初始化完了 monuted渲染完了
  2. 初始化实例的时候是父组件初始化完成后子组件才初始化 但是渲染的时候是子组件渲染完父组件才开始渲染 父created ->子created -> 子monted -> 父monted
  3. 更新的时候也是类似的 只有父组件触发更新 更新子组件 然后子组件更新完了 父组件才更新完 父before updated ->子before updated -> 子updated -> 父updated
  4. 同理 destroy也是

高级特性

自定义v-modle
  1. 首先父组件中在子组件中传入自定义v-module = “state” 子组件中代码如下

export default {
  model: { //自定义组件 prop对应props中的 event对应$emit中的值
      prop:'text1',//对应props  text
      event: 'change' 
   },
   props: {//接收父组件传递过来的 并设置默认值
      text1: String,
      default() {
         return :" "
       }
    }
}
$nextTick
  1. vue(react)是异步渲染
  2. data改变之后,DOM不会立即渲染
  3. $nextTick 会在DOM渲染以后被触发,以获取最新DOM节点
  4. 如果不使用 n e x t T i c k 在 通 过 nextTick 在通过 nextTickthis.refs获取DOM节点并不能获取最新的DOM节点
slot
  1. 在父组件中的子组件里写的内容 在子组件中应该使用slot插槽接收 如果不写的话 在父组件中的子组件里写的内容是不会在子组件中显示的‘
  2. 如果想在父组件中获取到子组件中的data值 这时候要用到作用域插槽了,代码演示如下
//父组件

   

//子组件./ScopedSlotDemo中
   
    export default {
      data(){
         return {
            website:{
               
             }
          }
       }
    }
  1. 具名插槽 slot中使用name 父组件中的template中v-slot对应子组件slot中的name
动态组件-左侧菜单右侧使用全组件对应左侧菜单来切换
异步组件
  1. 系统中使用比较大的组件的时候应该怎么异步加载
  2. import函数
  3. 按需加载,异步加载大组件 当用到的时候才会加载 比如 点击按钮显示的时候,在pc端所有的点击显示一个弹出列表组件的时候都可以用到
  4. 可以在父组件的components中使用 FormDemo: ()=>import(’…/FormDemo’)
  5. 优化性能
mixin
  1. 多个组件有相同的逻辑的时候抽离出来
  2. mixin并不是完美的解决方案,会有一些问题
  3. vue3提出的composition API旨在解决这些问题
  4. 使用方法可以在data(){}上方引入mixins:[myMixin],//可以添加多个 会自动合并起来 myMixin是一个js文件 里面可以写 data methods mounted等 引入的时候会与当前的 data methods mounted等 结合起来 可以自由的在当前页面使用
  5. 问题是 变量来源不明确 不利于阅读,多mixin可能会造成命名冲突,和组件之间可能出现多对多的关系,复杂度较高

Vue原理

组件化
  1. 传统组件,只是静态渲染,更新还要依赖于操作DOM
  2. 数据驱动视图 - Vue MVVM (M 模型 View视图 dom vm vue)
  3. 数据驱动视图 - React setState
Vue响应式
  1. 核心API - Object.defineProperty
  2. vue3.0后 会使用proxy替代Object.defineProperty 但是proxy兼容性不好,且无法polyfill
  3. Object.defineProperty 如果深度监听需要递归到底,一次性计算量最大
  4. 无法监听新增/删除属性 (vue3.0之前需要使用Vue.set Vue.delete)
  5. 不具备监听数组的能力 这时候需要重新定义数组原型
//重新定义数组原型
const oldArrayProperty = Array.prototype
//创建新对象,原型指向oldArrayProperty,再扩展新的方法不会影响原型
const = arrProto = Object.create(oldArrayProperty)
//然后写你要监听的变化的数组的方法 可以写很多 这里只写一个
['push'].forEach(methodName=>{
   arrProto[methodName] = function(){
     //调用监听方法
     jtff()
     //调用这个方法本来的API
     oldArrayProperty[methodName].call(this,...arguments)
   }
})
//然后判断传入defineProperty的参数是不是数组 如果是的话 参数.__proto = arrProto
vdom 和 diff
  1. 因为操作dom非常耗时 所以就有了后来的数据驱动视图,但是数据驱动视图普及开来之后,业务复杂度上升,对dom的操作并没有减少,反而增多了,因为js的执行速度要快得多,所以用js模拟dom结构,计算出最小改变的然后更改 这就是vdom。
  2. 用js模拟dom结构 tag:标签名 props:属性 类名 children:子元素 具体如下代码所示

vdom

  • a
//js模拟dom结构 { tag:"div", props: { className:"container", id:"div1" } children: [ { tag:"p", children:"vdom" }, { tag:"ul", props:{style:"font-size:20px"} } .... ] }
  1. 学习vdom可以通过snabbdom这个简洁强大的vdom库,易学易用,vue也是参考它实现的vdom和diff snabbdom
  2. diff算法是vdom中最核心,最关键的部分 能在日常使用中就体现出来 如vue react中的key
  3. 如果对比两颗树 平常的例子就是 遍历第一棵树,遍历第二课树 ,然后排序 时间复杂度是O(n^3) 基本不可用 因为如果有1000个节点 就要计算1亿次,冒泡排序是O(n ^ 2)
  4. vdom中的diff对比两棵虚拟dom树 是只比较同一层级,不跨级比较,当tag不相同,则直接删掉重建,不再深度比较,tag和key相同,则认为是相同节点,不再深度比较
  5. vdom中h函数是创建虚拟dom节点的函数,patch函数是对比的前后虚拟dom节点的函数,如果相同才会继续深层对比 如果不相同直接删掉重建,如果新的children有值 旧的没有值 那么在新的vNode上直接添加就行
  6. vdom中的updateChildren函数:如果新旧vNode两个都有children就执行此函数,具体对比方式可自己查询
  7. vdom核心概念:h, patch, vnode, diff, key, vdom存在的价值更重要:数据驱动视图,控制DOM操纵
模版编译
  1. 模版是vue中最常用的部分,既与实用相关联的原理,它不是html 有指令、插值、js表达式
  2. with函数 如下示例:
let obj  = { a:100, b:200 }
//使用with ,能改变{ } 内自由变量的查询结果
// 将 { } 内自由变量,当作obj的属性来调用
with(obj){
   console.log(a)//100
   console.log(b)//200
   console.log(c)//会报错
 } 
  1. html不是图灵完备语言 不能执行判断 循环 之类的 所以 模版一定是转化为了某种js代码,即编译模版 把模版编译为一个函数 with(this) this就是vue的实例 返回的是一个vnode
如果想要看 v-if v-for 在模版中经过js转化为什么样子可以创建一个文件 引入 
const compiler = require ("vue-template-compiler") 
然后在 写个 
consttemplate = `
//编译
const res = compiler.compile(template)`
console.log(res.render)
然后node 文件名就可以执行了
以上解析模版为render是在编译环境执行的 真实的vue是直接在开发环境就通过vue-loader编译好的
初次渲染过程
  1. 解析模版为render函数(或在开发环境已完成,vue-loader)
  2. 触发响应式,监听data属性getter setter(get只会触发跟视图有关系的 如果data中的属性 template都没用到 是不会触发get的)
  3. 执行render函数,生成vnode,patch( elem,vnode)
更新过程
  1. 修改data,触发setter(此前在getter中已被监听)
  2. 重新执行render函数,生成newVnode
  3. patch(vnode,newVnode)
  4. 渲染更新过程可看下图
    vue概略_第1张图片

高频vue面试题汇总

v-show 和 v-if的区别
  1. v-show 通过css display 控制显示隐藏
  2. v-if 组件真正的渲染和销毁,而不是显示和隐藏
  3. 频繁切换显示状态用v-show 否则用v-if
为何在v-for中使用key
  1. 必须使用key,且不能是index和random 如果是index的话插入比较还是没有意义
  2. diff算法中通过tag和key来判断,是否是sameNode
  3. 减少渲染次数,提升性能
vue组件通讯
  1. 父子组件 props和 this.$emit
  2. 自定义事件 event. n o e v e n t . no event. noevent.off event.$emit
  3. vuex
双向绑定v-model的实现原理
  1. input元素的value = this.name
  2. 绑定input事件的 this.name = $event.target.value
  3. data更新触发re-render
computed有什么特点
  1. 缓存 data不变不会重新计算
  2. 提升新能
为什么data必须是一个函数
  1. 因为vue是个类,在每个组件中使用这个类的时候相当于这个类的实例化,因为是一个函数就实现闭包功能 就不会相互影响
ajax请求应该放在哪个生命周期
  1. mounted
  2. js是单线程的 ajax异步获取数据
  3. 放在mounted之前没有用 没渲染完成 你就算请求过来数据又能怎么样,只会让逻辑更加混乱
如何将组件所有的props传递给子组件
  1. 通过$props
何时使用beforeDestory
  1. 解绑自定义事件event.$off
  2. 清除定时器
  3. 解绑自定义的DOM事件,如window scroll等
Vuex中action和mutation有何区别
  1. action中处理异步,mutation不可以
  2. mutation是做原子操作,每次做一个操作
  3. action可以整合多个mutation
如何配置异步路由加载
  1. path中写路由 components => import() 这样就行了
vue如何监听数组变化
  1. object.defineProperty不能监听数组变化
  2. 只有重新定义数组原型,重写push pop等方法,实现监听
  3. proxy可以原生支持监听数组变化
diff算法的时间复杂度
  1. O(n) 是在 O(n ^ 3)上做了优化 只对比同一层级的了
简述diff算法过程
  1. patch(elem,vnode) 和 patch(vnode,newVnode)
  2. patchVnode和 addVnodes和 removeVnodes
  3. updateChildren(key的重要性)
Vue常见性能优化方式
  1. 合理使用v-show和v-if
  2. 合理使用computed
  3. v-for时加key,以及避免和v-if同时使用
  4. 自定义事件,DOM事件及时销毁
  5. 合理使用异步组件
  6. 合理使用keep-alive
  7. data层级不要太深
  8. 使用webpack
  9. 使用ssr
Proxy实现响应式
const data = {
  name: " zhangsan",
  age:20 
}
//proxy的基本使用
const proxyData = new Proxy(data, {
   get(target, key, receive) {
       const result = Reflect.get(target,key, receive)
       console.log('get',key)
       return result //返回结果
     },
     set(target, key, val,receive) {
       const result = Reflect.get(target,key,val, receive)
       console.log('get',key,val)
       return result //设置成功
     },
     deleteProperty(target, key) {
       const result = Reflect.deleteProperty(target,key)
       console.log('delete property',key)
       return result //是否删除成功
     },
 })
 //其中 Reflect的作用是和proxy的能力一一对应 更规范化、标准化、函数式 以后会慢慢替代掉Object上的工具函数
 //proxy相比defineProperty 来说 实现深度监听的时候 defineProperty需要一次递归完成 比较消耗性能 而 proxy可以只递归到get的层级

你可能感兴趣的:(vue)