Vue的两个版本
| Vue完整版 | runtime版 | |
|---|---|---|
| 特点 | 有编译器(compiler) | 没有编译器(compiler) |
| 视图 | 写在HTML或者 template 选项 | 写在 render 函数里,用 h 来创建标签 |
| cdn引入 | vue.min.js | vue.runtime.min.js |
| webpack引入 | 需要配置alias | 默认使用此版本 |
| @vue/cli引入 | 需要额外配置 | 默认使用此版本 |
template 和 render 怎么用
template:一个字符串模板作为 Vue 实例的标识使用。模板将会替换挂载的元素。挂载元素的内容都将被忽略。
render:字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个 createElement 方法作为第一个参数用来创建 VNode。
如果组件是一个函数组件,渲染函数还会接收一个额外的 context 参数,为没有实例的函数组件提供上下文信息。
Vue实例
如何使用Vue实例
从HTML得到视图
用的是『完整版Vue』
从CDN引用vue.js或vue.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数据响应式
首先我们需要了解getter和setter的用法
具体文档:对象初始化 - 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怎么办?
有两种情况:
- Vue会给出一个警告
- Vue只会检查第一层属性,只要由obj则不会报错,但是对于n的操作不会执行
解决办法
- 使用之前把key都设置好
- 使用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