原稿:语雀 · Vue 知识点 · 原目录:Vue › Vue 知识点

组件通信

通信方式10种

组件通信 父子通信【父 → 子】props子组件设置 props,父组件通过 v-bind 向子组件传递数据【子 → 父】vm.$emit子组件通过 $emit 触发子实例的事件,父组件使用 v-on 监听子实例事件并指定回调函数,通过 $emit 传递的参数可以使用 $event访问,或被父组件回调接… Front-end Baby👶

Vuex 和单纯的全局对象的区别

Vuex 和全局对象主要有两大区别:响应式 & 提交更改的方式 2. Vuex 的状态存储是响应式的:当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。 4. 不能直接改变 store 中的状态:改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

Vuex 的 mutation 中为什么不能异步

Vuex 中所有的 state 更新的唯一途径都是 mutation,异步操作必须通过 Action 提交 mutation 实现。

  • actions 只是一个架构性的概念,并不是必须的,说到底只是一个函数,在里面想干嘛都可以,只要最后触发 mutation 就行。异步竞态怎么处理那是用户自己的事情。
  • vuex 真正限制的只有 mutation 必需同步,每个 mutation 执行完成后都会对应到一个新的状态变更,这样 devtools 就可以打个快照存下来,然后就可以实现 time-travel 了。如果 mutation 支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。

Vuex 使用 记录下自己使用 Vuex 填的坑引入使用 ​npm install vuex -S​ 安装 vuex创建 /store 目录,其中创建子目录 /modules 和 index.js,子目录为了方便模块化使用 Vueximport Vue from “vue”; import Vuex from… Front-end Baby👶


生命周期

Vue 组件有哪些生命周期钩子?

参考链接:生命周期钩子图示  生命周期钩子 API

beforeCreate

在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用

完成以下配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调

created

在实例创建完成后被立即调用。然而,挂载阶段还没开始,$el property 目前尚不可用

  1. 判断是否有 el 属性,若存在,实例立即进入编译过程,否则,需显式调用 vm.$mount() 手动开启编译
  2. 判断是否有 template 属性,若存在则编译为 render 函数,否则将 el 的 outerHTML 编译为模板

beforeMount

在 mountComponent 中,创建 watcher 之前被调用:此时 el 属性可访问,但执行的是挂载的目标 DOM

实例完成挂载,el 被新创建的 vm.$el 替换

mounted

实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.$el 也在文档内

beforeUpdate

数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器

完成由于数据更改导致的虚拟 DOM 重新渲染和打补丁(patch)

updated

这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之

beforeDestroy

实例销毁之前调用。在这一步,实例仍然完全可用

销毁 watchers、子组件、事件监听器

destroyed

实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁

<keep-alive> 有自己独立的钩子函数 activated 和 deactivated,见 Keep-alive 与路由切换

Vue 的父子组件生命周期钩子执行顺序

渲染过程:

父组件挂载完成一定是等子组件都挂载完成后,才算是父组件挂载完,所以父组件的mounted在子组件mouted之后

父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted

子组件更新过程: 2. 影响到父组件:父beforeUpdate -> 子beforeUpdate->子updated -> 父updated 4. 不影响父组件:子beforeUpdate -> 子updated

父组件更新过程: 2. 影响到子组件:父beforeUpdate -> 子beforeUpdate->子updated -> 父updated 4. 不影响子组件:父beforeUpdate -> 父updated

销毁过程:

父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

不管是哪种情况,都一定是父组件等待子组件完成后,才会执行自己对应完成的钩子

可以使用 console.log 查看钩子执行情况

生命周期钩子 以 此处为语雀文档,点击链接查看:https://www.yuque.com/go/doc/26497725 中 1.5.2 版本的代码为例子,在 app 和组件下加入钩子函数,给 app 实例的 data 加一个 message propVue.component(“my-todo-list… Front-end Baby👶

小结:

  1. 除了 beforeCreate 和 destroyed 外的钩子执行时,data prop 都可以访问
  2. 除了 beforeCreate、created 和 destroyed 外的钩子执行时 this.$el 都可以访问

钩子与重要节点

new Vue() -> initMixin()
                        -> initLifecycle(vm)
                            -> initEvents(vm)
                            -> initRender(vm)
                            -> callHook(vm,"beforeCreate");
                            -> initState(vm)
                                    -> initData()/initMethods()/initComputed()/initWatch()
                            -> callHook(vm,"created");
              -> vm.$mount()  -> compileToFunctions()
                              -> mountComponent()
                                    -> callHook(vm,"beforeMount");
                                    -> new Watcher()
                              -> callHook(vm,"mounted");
  • beforeCreate() 前:实例初始化,数据观测未开始、方法、计算属性、侦听回调都未初始化
  • created() 前:数据观测完成、方法、计算属性、侦听回调初始化完成
  • beforeMount() 前:完成模板编译,即将创建 watcher 开始渲染
  • mounted() 前:完成渲染

属性和指令

v-show 对比 v-if

  • v-if 会在切换过程中对条件块的事件监听器和子组件进行销毁和重建,如果初始条件是 false,则不会渲染该 DOM,直到条件第一次为 true 时才开始渲染模块(惰性)
  • v-show 只是基于 css 进行切换,不管初始条件是什么,都会渲染。带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display
<h1 v-show="ok">Hello!</h1>

总结:v-if 切换的开销更大,而 v-show 初始化渲染开销更大,在需要频繁切换,或者切换的部分 DOM 很复杂时,使用 v-show 更合适。渲染后很少切换的则使用 v-if 更合适

computed 对比 watch

  • computed 计算属性,是依赖其他属性的计算值,作为新的属性,有缓存,只有当依赖的值变化时才会更新,需显式返回
  • watch 是在监听的属性发生变化时,在回调中执行一些逻辑,该属性本身存在于 data 或 prop 中

选择:

  • computed 适合在模板渲染中,某个值是依赖了其他的响应式对象甚至是计算属性计算而来,比如 Vuex 中的 getters 和通过 map 函数引入,映射为组件的计算属性
  • watch 适合监听某个值的变化去完成一段复杂的业务逻辑(计算属性适合作为计算值、监听适合执行复杂回调)
<div id="demo">{{ fullName }}</div>
// 计算属性版本
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})
// 侦听属性版本
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})

computed 对比 methods

  • 计算属性是基于他们的响应式依赖进行缓存的,在依赖发生变化时,会响应式地计算求值
  • methods 需要被调用,每次都会执行相应的方法

Vue 中 v-html 会导致什么问题

v-html 的作用:更新元素的 innerHTML,按普通 HTML 插入,而不会作为 Vue 模板进行编译。在网站上动态渲染任意 HTML,很容易导致 XSS 攻击。所以只能在可信内容上使用 v-html,且永远不能用于用户提交的内容上。

下例中,假设组件的 rawHtml prop 值为 <span style=“color:red”></span>,则使用 {{}} 会把该值解析为文本,但使用 v-html 则会编译这段 innerHTML