Vue 学习笔记

简介

Vue 是一个用于构建 Web 用户界面的渐进式 JavaScript 框架。其核心库只关注视图层(view layer),同时具备良好的第三方支持库生态用以应付构建复杂大型单页应用(SPA:Single-Page Application)。

MVVM 模型

Vue 虽然没有完全遵循 MVVM(Model-View-ViewModel)模型,当其设计也受到了 MVVM 的启发,以数据驱动界面,如下图所示:

Vue 学习笔记_第1张图片
Vue MVVM

在 Vue 中,充当 ViewModel 的是一个 Vue 实例(new Vue({})),该
Vue实例 作用于某一个 HTML 元素上,全权代理该元素节点的所有操作。

Vue实例 内部通过 DOM Listeners 可以观测到页面上 DOM 元素的变化,从而将该种变化同步更改到 Model 中的对应数据。
同时通过 Data Bindings,当 Model 中的数据改变时,则会对相应视图上的显示进行更改,从而实现了 View 和 Model 的数据双向绑定。

:传统的 Web 编程模型是 结构驱动,即要对一个 DOM 节点进行操作,第一步就是要获取该 DOM 节点对象,然后再修改数据更新到节点上。
而 Vue 的中心思想是 数据驱动,要更改界面,其实就是要更改数据。
简而言之,在 Vue 中,不应当考虑操作 DOM,而是专注于 操作数据

安装

Vue 的安装有多种方法,这里主要介绍两种方法:

  1. 通过

    :通过

    • 局部组件:对于全局组件来说,即使页面没有使用该组件,组件也会被注入到最终的构建结果中,导致了 JavaScript 文件的无谓增加。而局部组件可以做到按需加载,需要哪些组件,按需引入即可,更加灵活高效。
      定义方式:通过一个普通的 JavaScript 对象来定义组件,然后 Vue实例 按需引入需要的组件即可。
    
        

    最佳实践:在 Vue 中,组件通常都定义到一个单独的.vue文件中,其他组件需要时,导入相应组件的.vue文件即可。

    // MyComponent.vue
    
    
    
    
    
    

    可以直接使用以下命令直接运行.vue文件,查看组件展示效果:

    vue serve MyComponent.vue --open
    

    也可以在其他组件内导入该组件,进行使用:

    
    
    
    

    :在 Vue 中,组件实质是带有一个名字的 Vue实例,其性质与 Vue实例 基本一致(遵循 Vue实例 的生命周期等内容),特点是多了个组件复用功能。

    Vue实例

    Vue 实例充当 ViewModel 角色,负责 View 和 Model 之间的数据绑定:

    new Vue(Options)
    

    当创建一个 Vue 实例时,你可以传入一个选项对象Options,该Options的选项列表有如下可选:

    • 选项 / 数据
    • 选项 / DOM
    • 选项 / 生命周期钩子
    • 选项 / 资源
    • 选项 / 组合
    • 选项 / 其他

    下面列举一些Options常用选项

    • 选项 / 数据:data
      描述:Vue 实例的数据对象,用于数据的存储与显示。
      类型:Object | Function
    
        

    {{message}}

    :Vue 将会递归将data的属性转换为getter/setter,从而让data的属性能够响应数据变化。比如在控制台输入vm.message = 'Hi Vue!!!,可以观察到页面数据发生了更改。

    组件 中的data属性必须是Fcuntion类型,其返回一个Object,原因是组件复用时,保证每个新组件都有独一的一份数据拷贝。

    // MyComponent.vue
    
    
    
    
    • 选项 / 数据:props
      描述:该属性用于接收来自父组件的数据。
      类型:Array | Object
      当传递的是Object类型时,则可以基于对象的语法使用以下选项:
      type:指定数据类型,该值可以为原生类型(StringNumberBooleanArrayObjectDateFunctionSymbol),自定义构造函数,或上述内容组成的数组。
      default:any:为该prop指定一个默认值。如果该prop没有被传入,则使用该默认值。对象或数组的默认值必须从一个工厂函数返回。
      required: Boolean:定义该prop是否为必填项。
      validator: Function:自定义验证函数,对该prop进行校验。
    Vue.component('my-component', {
      props: {
        // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
        propA: Number,
        // 多个可能的类型
        propB: [String, Number],
        // 必填的字符串
        propC: {
          type: String,
          required: true
        },
        // 带有默认值的数字
        propD: {
          type: Number,
          default: 100
        },
        // 带有默认值的对象
        propE: {
          type: Object,
          // 对象或数组默认值必须从一个工厂函数获取
          default: function () {
            return { message: 'hello' }
          }
        },
        // 自定义验证函数
        propF: {
          validator: function (value) {
            // 这个值必须匹配下列字符串中的一个
            return ['success', 'warning', 'danger'].indexOf(value) !== -1
          }
        }
      }
    })
    
    • 选项 / 数据:propsData
      描述:创建实例时传递props。主要作用是方便测试。
      类型:{ [key: string]: any }
    var Comp = Vue.extend({
      props: ['msg'],
      template: '
    {{ msg }}
    ' }) var vm = new Comp({ propsData: { msg: 'hello' } })

    propsData属性只能用于new创建的实例中。

    • 选项 / 数据:methods
      描述:方法定义,Vue实例 可以直接访问这些方法,或在指令表达式中直接调用这些方法。
      类型:{ [key: string]: Function }
    var vm = new Vue({
      data: { a: 1 },
      methods: {
        plus: function () {
          this.a++
        }
      }
    })
    vm.plus()
    vm.a // 2
    

    methods中的this自动绑定到当前 Vue实例。

    • 选项 / 数据:computed
      描述:计算属性,主要用于对data数据进行计算转换。
      类型:{ [key: string]: Function | { get: Function, set: Function } }
    
    
    
    

    computed类型为Object,其具有如下特点:

    1. computed内部定义的属性为访问器属性,即具备gettersetter,且其内部this自动绑定到当前 Vue实例。
    2. computed会自动 缓存 计算结果,只有当依赖的响应式属性变化时,coputed才会重新进行计算。缓存computedmethods的最大区别之处,methods每次调用一定会运行函数,而computed则不一定。
    • 选项 / 数据:watch
      描述:侦听属性,用于监控datacomputed的数据,当数据变更时进行回调通知。
      类型:{ [key: string]: string | Function | Object | Array }
      watch类型为Object,其内部属性的类型有多种:string | Function | Object | Array,这里简单介绍 3 种:
    1. string:字符串表示回调函数名,当数据改变时,回调该函数:
    const vm = new Vue({
        el: '#app',
        data: {
            a: 1
        },
        methods: {
            aChanged(value, oldValue) {
                console.log(`a changed: new:${value} --> old:${oldValue}`);
            }
        },
        watch: {
            a: 'aChanged'
        }
    });
    
    1. Function:当数据改变时,直接回调该函数:
    const vm = new Vue({
        el: '#app',
        data: {
            a: 1
        },
        watch: {
            a(value, oldValue) {
                console.log(`a changed: new:${value} --> old:${oldValue}`);
            }
        }
    });
    
    1. Object:对监控的属性为对象时,Vue 默认只能监控到对象重新被赋值的变化,而如果需要监听对象内部属性的变化,则可使用该选项,其中:
      handler代表回调函数。
      deep用来控制监听对象属性的层级,deep=true时只要对象内部 property 改变(不管嵌套有多深),都会监听到。
      immediate用来设置是否立即产生回调。当immediate=true时,回调函数会立即被调用,传递的是属性当前的值。
    const vm = new Vue({
        el: '#app',
        data: {
            a: {
                aa: {
                    aaa: 3
                }
            }
        },
        watch: {
            a: {
                handler(value, oldValue) {
                    console.log(`a changed: new:${value} --> old:${oldValue}`);
                },
                deep: true // 被监听对象的 property 改变时被调用,无论嵌套的有多深
            }
        }
    });
    

    :大多数情况下,观察和响应数据变更使用计算属性(computed)便足够了,但是当在数据变化时需要执行异步或开销较大的操作时,则此时使用侦听属性(watch)会更加适合。

    • 选项 / DOM:el
      描述:设置 Vue实例 的挂载目标节点
      类型:string | Element
    new Vue({
        el: '#app'
    });
    

    :如果在实例化时存在这个选项,实例将立即进入编译过程,否则,需要显式调用vm.$mount()手动开启编译。

    • 选项 / DOM:template
      描述:字符串模板,模板会 替换 挂载的元素。
      类型:string
    const vm = new Vue({ el: '#app', template: '

    template

    ' //
    会被

    完全覆盖 })

    • 选项 / DOM:render
      描述:字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个createElement方法作为第一个参数用来创建VNode
      类型:(createElement: () => VNode) => VNode
    new Vue({ render(createElement) { return createElement('div', { class: 'rendered' }, [ createElement('h1', { domProps: { innerHTML: 'div>h1 rendered by vue' } }) ] ); }}).$mount('#app');

    :Vue 推荐在绝大多数情况下使用模板来创建你的 HTML,只有在一些特殊场景下,比如模板冗长且具备重复元素,则此时使用渲染函数render通过编写 JavaScript 代码来渲染出页面会更加方便简洁。

    • 选项 / 生命周期钩子:见下文

    生命周期

    每个 Vue实例 在挂载到页面时,都会经历一系列的初始化过程,例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。在创建 Vue实例 的这整个过程中,Vue 为我们预留出了一些 Hook 点,方便我们在 Vue实例 创建过程的某个生命周期中进行一些操作。如下图所示:

    Vue 学习笔记_第3张图片
    vue lifecycle

    :图片来源于网上,侵删。

    这些预留的生命周期钩子函数总共有如下几个:

    • beforeCreate:Vue实例 初始化之后,此时datamethods中的数据还未进行初始化,因此无法获取。

    • created:表示 Vue实例 创建完成,但还未挂载到页面上,此时datamethods都已经初始化成功,可以对其进行调用获取,而挂载阶段未开始,所以$el属性目前不可见。

    • beforeMount:在挂载开始之前被调用,此时模板已在内存中被编译完成,只是尚未挂载到页面上,因此,此时页面上显示的还是未渲染的结构。

    • mounted:挂载完成,此时页面会显示我们渲染的视图。如果想要操作页面上的 DOM 节点,最早的时间就是该处。
      mounted不会 承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用vm.$nextTick替换掉mounted

    mounted: function () {
      this.$nextTick(function () {
        // Code that will run only after the
        // entire view has been rendered
      })
    }
    
    • beforeUpdate:数据更新时调用,此时内存中data数据已更新,但页面中显示的数据还未更新,数据与页面不同步。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。

    • updated:新数据成功渲染到页面,此时数据与页面处于同步状态。
      updated不会 承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用vm.$nextTick替换掉mounted

    • activated:激活状态,表示当前组件处于前台页面,用户可与该组件进行交互。
      :只有组件被内置组件keep-alive包裹时,该钩子才有可能被调用。

    
    
    • deactivated:停用状态,表示当前组件处于后台页面,用户不能与之交互。
      :只有组件被内置组件keep-alive包裹时,该钩子才有可能被调用。

    • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用,即此时实例的datamethods等所有数据完全可用。

    • destroyed:Vue 实例销毁后调用。此时 Vue实例 指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

    • errorCaptured:当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回false以阻止该错误继续向上传播。

    指令

    指令 (Directives) 是带有v-前缀的特殊属性。

    Vue 提供了以下内置的指令:

    • v-text:更新元素的textContent,该指令与使用{{ Mustache }}插值效果一样。
      类型:string
    
    
    {{msg}}
    
    • v-html:更新元素的innerHTML
      类型:string
    
    
    
    

    v-html的内容只会按普通 HTML 插入,不会作为 Vue 模板进行编译。
    :在单文件组件里,scoped 的样式不会应用在 v-html 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。
    :在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 XSS 攻击。只在可信内容上使用v-html,永不用在用户提交的内容上。

    • v-show:条件渲染,根据表达式之真假值,切换元素的displayCSS 属性。
      类型:any

    Hello!

    v-show不支持