Vue 2 笔记

269 阅读3分钟

Vue的两个版本

Vue完整版runtime版
特点有编译器(compiler)没有编译器(compiler)
视图写在HTML或者 template 选项写在 render 函数里,用 h 来创建标签
cdn引入vue.min.jsvue.runtime.min.js
webpack引入需要配置alias默认使用此版本
@vue/cli引入需要额外配置默认使用此版本

template 和 render 怎么用

template:一个字符串模板作为 Vue 实例的标识使用。模板将会替换挂载的元素。挂载元素的内容都将被忽略。

render:字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个 createElement 方法作为第一个参数用来创建 VNode

如果组件是一个函数组件,渲染函数还会接收一个额外的 context 参数,为没有实例的函数组件提供上下文信息。

Vue实例

如何使用Vue实例

从HTML得到视图

用的是『完整版Vue』
从CDN引用vue.jsvue.min.js即可做到
也可以通过import引用vue.js或vue.min.js

从JS构建视图

使用vue.runtime.js
这种方法虽然用起来不方便,但更加独立且体积更小,因为没有编译器compiler

使用vue-loader

可以把.vue文件翻译成h构建方法
但这样做HTML就只有一个div,SEO不友好。


把Vue实例命名为vm是尤雨溪的习惯
vm对象封装了对视图的所有操作,包括数据读写时间绑定DOM更新
vm的构造函数是Vue,按照ES6的说法,vm所属的类是Vue
options是new Vue的参数,一般称之为选项构造选项

options里面有什么

options的五类属性

  • 数据:data、props、propsData、computed、methods、watch
  • DOM:el、template、render、renderErr
  • 生命周期钩子:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、activated、deactivated、beforeDestroy、destroyed、errorCaptured
  • 资源:directives、filters、components
  • 组合:parent、mixins、extends、provide、inject
  • 其他

参考Vue2官方文档:API — Vue.js (vuejs.org)


常用属性

el - 挂载点

提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。可以使用$mount代替。

data - 内部数据

支持对象和函数,优先使用函数,防止组件重复调用时,data属性被篡改。

methods - 方法

事件处理函数或者普通函数

new window.Vue({
    data() {
        return {
            n: 0,
            array: [1, 2, 3, 4, 5, 6]
        };
    },
    template: `
      <div class="red">{{ n }}
      <button @click="add">+1</button>
      <hr>
      {{ filter() }}   
      </div>`,
    methods: {
        add() {
            this.n += 1;
        },
        filter() {
            return this.array.filter(i => i % 2 === 0); 
            //此处的filter不是Vue的,是数组本身的方法
        }
    }
}).$mount('#app');

components

Vue组件,注意大小写
三种引入方式:
1.推荐使用这种引入方式

import myDemo from './myDemo';  //引用一个.vue文件作为组件
new window.Vue({
    components: {
        Demo: myDemo
    }, data() {
        return {
            n: 0, array: [1, 2, 3, 4, 5, 6]
        };
    }, template: `
    <div class="red">{{ n }}
    <button @click="add">+1</button>
    <hr>
    {{ filter() }}
    <hr>
    <Demo/>
    //添加组件
    </div>`, methods: {
        add() {
            this.n += 1;
        }, filter() {
            return this.array.filter(i => i % 2 === 0);
        }
    }
}).$mount('#app');
window.Vue.component('Demo2', {
    template: `
    <div>demo2</div>
    `
});
new window.Vue({
    data() {
        return {
            n: 0, array: [1, 2, 3, 4, 5, 6]
        };
    }, template: `
    <div class="red">{{ n }}
    <button @click="add">+1</button>
    <hr>
    {{ filter() }}
    <hr>
    <Demo2/>
    </div>`, methods: {
        add() {
            this.n += 1;
        }, filter() {
            return this.array.filter(i => i % 2 === 0);
        }
    }
}).$mount('#app');
new window.Vue({
    components: {
        Demo3: {
            template: `
            <div>Demo3</div>
            `
        }
    }, data() {
        return {
            n: 0, array: [1, 2, 3, 4, 5, 6]
        };
    }, template: `
    <div class="red">{{ n }}
    <button @click="add">+1</button>
    <hr>
    {{ filter() }}
    <hr>
    <Demo3/>
    </div>`, methods: {
        add() {
            this.n += 1;
        }, filter() {
            return this.array.filter(i => i % 2 === 0);
        }
    }
}).$mount('#app');

四个生命周期钩子

  • created:实例出现在了内存中
  • mounted:实例出现在页面中
  • updated:实例更新了
  • destroyed:实例从页面和内存中消亡了

props - 外部数据

  • 也叫属性
  • message="n"传入字符串
  • :message="n"传入this.n数据
  • :fn="add"传入this.add函数

Vue数据响应式

首先我们需要了解gettersetter的用法

具体文档:对象初始化 - JavaScript | MDN (mozilla.org)

let obj = {
    姓: '程',
    名: '咬金',
    get 姓名() {
        return this.姓 + this.名;
    },
    set 姓名(name) {
        this.姓 = name[0];
        this.名 = name.slice(1);
    }
};

如果需要在已经定义好的对象上添加get和set,则需要用到:
Object.defineProperty()

var _xxx = 0;     //此处的_xxx作为一个容器存取值
Object.defineProperties(obj, 'xxx', {     //此处的xxx属性并不存在
    get() {
        return _xxx;
    }
    set(value) {
        _xxx = value;
    }
});

使用代理

let data = proxy({n: 0}); // 括号里是匿名对象,无法访问

function proxy({data}/* 解构赋值,别TM老问 */) {
    const obj = {};
    Object.defineProperty(obj, 'n', {
        get() {
            return data.n;
        },
        set(value) {
            if (value < 0) return;
            data.n = value;
        }
    });
    return obj; // obj 就是代理
}

// data就是 obj

使用监听和代理

let myData5 = {n: 0};
let data5 = proxy2({data: myData5}); // 括号里是匿名对象,无法访问

function proxy2({data}) {
    let value = data.n;
    Object.defineProperty(data, 'n', {
        get() {
            return value;
        },
        set(newValue) {
            if (newValue < 0) return;
            value = newValue;
        }
    });
    // 就加了上面几句,这几句话会监听 data

    const obj = {};
    Object.defineProperty(obj, 'n', {
        get() {
            return data.n;
        },
        set(value) {
            data.n = value;
        }
    });
    return obj;
}

小结

Object.defineProperty

可以给对象添加属性value
可以给对象添加getter/setter
getter/setter用于对属性的读写进行监控

代理(设计模式)

对myData对象的属性读写,全权由另一个对象vm负责
vm就是myData的代理
例如使用vm.n来操作myData.n

vm = new Vue({data:myData})

首先会让vm成为myData的代理(proxy)
其次会对myData的所有属性进行监控
为什么需要监控?为了防止myData的属性发生变化,vm不知道 vm在知道myData属性变更之后,会调用render(data)

什么是响应式

若一个物体对外界的刺激作出反应,他就是响应式的

Vue的data是响应式

const vm = new Vue ({data:{n:0}})
我如果修改vm.n,那么UI中的n就会响应
Vue2通过Object.defineProperty来实现数据的响应式

Object.defineProperty的问题

Object.defineProperty(obj,'n'.{...})
必须要由一个'n',才能监听和代理obj.n,但是如果没有给n怎么办?

有两种情况:

  1. Vue会给出一个警告
  2. Vue只会检查第一层属性,只要由obj则不会报错,但是对于n的操作不会执行

解决办法

  1. 使用之前把key都设置好
  2. 使用Vue.set 或者this.$set

Vue.set和this.$set作用

this.$set(this.obj,'m',100)

  • 新增key
  • 自动创建代理和监听(如果没有创建过)
  • 触发UI更新(但不会立刻更新)

总结

  • 对象中新增的key

Vue没有办法事先监听和代理
要使用set来新增key,创建监听和代理,更新UI
最好提前把属性都写出来,不要新增key
但是数组做不到不新增key

  • 数组中新增的key

用set新增key,会更新UI,但不会创建监听和代理
Vue作者尤雨溪篡改了7个API方便对数组的进行增删
这7个API会更新UI,但不会自动处理监听和代理
this.array[n]=xxx,既不会更新UI,也不会自动处理监听和代理
所以数组新增key最好通过7个API