头图

Vue

对Vue的理解

Vue 是一个构建数据驱动的渐进性框架,目标是通过API实现 响应数据绑定视图更新

Vue的两大核心

  • 数据驱动
  • 组件系统

    Vue生命周期

    Vue实例从创建到销毁的过程
    graph LR
    开始创建 --> 初始化数据-->编译模板-->挂载DOM-->渲染-->更新-->渲染;更新-->卸载

    生命周期的作用

    生命周期中有多个事件钩子,能让开发者在控制整个vue实例的过程时更容易形成良好的逻辑判断

    createdmounted

createdmounted
调用时机模板渲染成 HTML 前模板渲染成 HTML 后
常见作用初始化属性值,再渲染成视图操作DOM节点

定时器

beforeDestroy()清除

clearInterval(this.timer);
this.timer = null;

v-model的使用

用于表单数据的双向绑定,其实是语法糖,背后做了两个操作:

  1. v-bind绑定value属性
  2. v-on绑定input事件

    Vue响应式(双向数据)原理

    通过 数据劫持 结合 发布订阅模式 的方式来实现

  3. Vue2:通过Object.defineProperty() 来劫持各个属性的setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调
  4. Vue3:仅仅是将数据劫持的方式由Object.defineProperty更改为ES6的Proxy代理

    Vue3相对Vue2的优化

  5. 双向数据绑定方面:
    Vue2的object.defineProperty一次只能劫持对象的单个属性,从而需要通过递归+遍历对每个对象的每个属性进行数据监控;如果属性值是对象的话,还需要深度遍历
    而Vue3.0中的proxy可以一次性地劫持对象的所有属性的setter、getter,还可以代理数组,也可以代理动态添加的属性,有13种劫持操作
  6. 性能方面快1.2~2倍:

(1) diff方法优化

vue2中的虚拟dom是全量的对比(每个节点不论写静态还是动态的都会比较)

vue3新增了静态标记(patchflag)与上次虚拟节点对比时,只对比带有patch flag的节点(动态数据所在的节点);可通过flag信息得知当前节点要对比的具体内容

(2) 静态提升

vue2无论元素是否参与更新,每次都会重新创建然后再渲染
vue3对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用即可

(3) 时间侦听器缓存

默认情况下onClick会被视为动态绑定,所以每次都会追踪它的变化

但是因为是同一个函数,所以不用追踪变化,直接缓存起来复用即可

(4) ssr渲染

  1. 按需编译,体积比vue2.x更小
  2. 组合API(类似react hooks)
  3. 更好的Ts支持
  4. 暴露了自定义渲染API
  5. 更先进的组件
  6. Fragment:模板可以有多个根元素

    虚拟DOM

    虚拟DOM相对于浏览器所渲染出来的真实 DOM,在 React,Vue 等技术出现之前, 改变页面展示内容只能遍历查询 DOM 树找到需要修改的 DOM,然后修改样式行为或者结构,来更新UI,但是这种方式相当消耗计算资源,每次查询DOM几乎都需要遍历整棵DOM树,因此建立一个与真实DOM树对应的虚拟DOM对象(JavaScript对象),以对象嵌套的方式来表示DOM树,那么每次DOM的更改就变成了对象属性的更改,这样一来就能通过diff算法查找变化要比查询真实的DOM树的性能开销小

    <template>渲染过程

    graph TD
    将template标签里面的内容编译成render函数 --> 挂载实例:根据render函数的根节点递归生成虚拟DOM树-->通过diff算法对比虚拟DOM,渲染到真实DOM-->新的DOM操作使得DOM树发生改变-->通过diff算法对比虚拟DOM,渲染到真实DOM

    key的作用

    为了高效的更新虚拟DOM

给虚拟DOM的每个节点 VNode 添加唯一 id,让其可以依靠 key,更快速准确地拿到 oldVnode 中对应的 VNode

【设置key不推荐使用index或者随机数,因为增删子项的时候损耗性能较大】

v-ifv-show

  • v-if在DOM层面决定元素是否存在,会引起重排重绘
  • v-show在CSS层面决定是否将元素渲染出来(实际上该元素一直存在)

    v-ifv-for优先级

v-ifv-for
Vue 2 优先
Vue 3优先

解决方案 :

  1. 父元素使用v-if,子元素使用v-for
  2. 使用计算属性computed
computed() {
    list() {
        return [1, 2, 3].filter(item => item !== 2);
    }
}

data是个函数并且返回一个对象 / data为什么要用return

因为一个组件可能会多处调用,每次调用会执行data函数并返回新的数据对象,因此这样可以避免多处调用之间的数据污染

Vue 如何监听键盘事件

  1. @keyup.方法
  2. addEventListener

    组件通信

  3. 父子的传参及方法调用:props / &dollar;emit、&dollar;parent / &dollar;children
  4. 祖孙的传参:provide / inject API、&dollar;attrs / $listeners
  5. 兄弟的传参:bus.js、Vuex
  6. 路由的传参:query、params
父子祖孙/隔代兄弟
props / $emit
ref与 &dollar;parent / &dollar;children
&dollar;attrs / $listeners
provide / inject
EventBus(&dollar;emit / $on)
Vuex

localStorage/Cookie等都可以

删除数组用 delete 和 Vue.delete 的区别

  • delete:只是被删除数组成员变为 empty / undefined,其他元素键值不变

    • Vue.delete:直接删了数组成员,并改变了数组的键值
      (对象是响应式的,确保删除能触发更新视图,这个方法主要用于避开 Vue 不能检测到属性被删除的限制)

计算属性computed和属性检测watch

cpmputed:当且仅当计算属性依赖的 data 改变时才会自动计算
computedwatch
首次运行×
默认依赖深度(推荐使用)浅度
调用时在模板渲染只需修改元数据
合适性筛选、不可异步开销较大、异步操作
特征根据页面变化而变化(用于计算)监听页面状态而变化(用于监听)

Vue组件封装过程

graph LR
Vue.extend&nbsp创建组件-->Vue.component&nbsp注册组件

v-for后使用this.$refs报错domundefined

组件初始化到第一次渲染完成的mounted周期里,只是渲染了组件模板的静态数据,并没有初始化动态绑定的dom,所以在mounted周期里面操作获取不到dom

解决方法:

  1. 把this.$nextTick放在获取到v-for绑定的数据并赋值之后,也就是触发响应式更新之后再进行操作
  2. 把操作dom的操作放到updated生命周期里,但是这样每次更新视图都会触发该操作

    scoped的实现原理

  3. 通过PostCSS给所有dom都添加了唯一的动态属性
  4. 通过PostCSS也给css选择器额外添加对应的属性选择器,来选择组件中的dom

    插槽

  5. 默认插槽
  6. 具名插槽
  7. 作用域插槽

    Vue CLI

    src目录每个文件夹和文件的用法

  8. assets文件夹是放静态资源;
  9. components是放组件;
  10. router是定义路由相关的配置;
  11. app.vue是一个应用主组件;
  12. main.js是入口文件

    static和assets的区别

    原理:webpack 如何处理静态资源

    staticassets
    内容类库项目资源
    资源直接引用被 webpack 打包

(static放别人家的资源,assets放自己家的资源)

引入第三方库

  1. 绝对路径直接引入
  2. 在 webpack 中配置 alias [ˈeɪliəs]
  3. 在 webpack 中配置 plugins [ˈplu:genz]

    Vue-Router

    路由实现原理

  4. 利用URL中的hash("#")
  5. 利用History interface在HTML5中新增的方法

    hash模式和history模式

    hash模式history模式
    浏览器支持版本IE、低版本HTML5新推出的API
    刷新重新加载404
    URL中是否带 #×
    # 后面的hash变化不会重新加载,会触发hashchange事件渲染对应内容重新加载,会触发popState事件渲染对应内容

传参

  • name 传参
  • URL 传参
  • <router-link>的to传参
  • 用 path 匹配路由,通过 query 传参

    二级路由 / 嵌套路由哦

    使用路由导航<router-link>和路由容器<router-view>,配置children

    路由守卫触发流程

  • 不同组件(A组件跳转到B组件)

    graph TD
    触发导航-->调用A组件的路由守卫beforeRouteLeave-->调用全局路由前置守卫beforeEach-->调用B路由独享守卫beforeEnter-->解析异步路由组件B-->调用B的组件内路由守卫beforeRouteEnter-->调用全局路由解析守卫beforeResolve-->确认导航-->调用全局路由钩子afterEach-->渲染B组件DOM

    keep-alive

    keep-alive用于保存组件的渲染状态

不希望组件被重新渲染影响用户体验和降低性能,而是希望组件可以缓存下来,维持当前的状态,这时候就可以用到keep-alive组件

(通常搭配生命周期activated使用)

keep-alive是一个抽象组件:它自身不会渲染一个DOM元素,也不会出现在父组件链中;使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
简单来说就是:应用遇到多个组件共享状态时,使用vuex。

vuex的流程

graph TD
页面通过&nbspmapAction&nbsp异步提交事件到&nbspaction-->action&nbsp通过&nbspcommit&nbsp把对应参数同步提交到&nbspmutation-->mutation&nbsp修改&nbspstate&nbsp中对应的值-->通过&nbspgetter&nbsp传递对应值-->在页面的&nbspcomputed&nbsp中通过&nbspmapGetter&nbsp来动态获取&nbspstate&nbsp中的值

vuex属性

mapAction:State , Getter , Mutation , Action , Module

  1. state:vuex的基本数据(state),用来存储变量
  2. getter:从基本数据(state)派生的数据,相当于state的计算属性
  3. mutation:提交更新数据的方法,必须是同步的(如果需要异步使用action)。每个mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。
  4. action:和mutation的功能大致相同
    不同之处:
  5. Action 提交的是 mutation,而不是直接变更状态
  6. Action 可以包含任意异步操作
  7. modules:模块化vuex,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构清晰,方便管理。

    ajax 写在 methods 中还是 actions 中

  8. 仅在请求组件内使用:写在组件的 methods 中
  9. 在其他组件复用:写在 vuex 的 actions 中
    (包装成 promise 返回,在调用处用 async await 处理返回的数据)

全栈冲冲冲
1 声望0 粉丝

知识不应该区别国界,每个人生活在这个美好的时代都应该贡献自己的价值,我们国内的程序员工程师都应该多学本职以外的IT知识,不要局限于应用层,让我国的IT行业更加茁壮成长