Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
将 Vue.js 添加到项目中主要有四种方式:
这样会直接使用最近版本
但是对于生产环境,最好使用明确的版本号和文件,防止盲目使用最新版本造成破坏
也可以使用Vue.extend进行实例化
var Profile = Vue.extend({});
var app = new Profile();
app.$mount("#hello");
Vue 实例的数据对象,Vue 会递归地把 data 的 property 转换为 getter/setter,从而让 data 的 property 能够响应数据变化。
var obj = {ele:{},num:1}
把上方这个对象放入vue实例中的data属性中会自动被处理成下方这样
getter/setter实际依赖于Object.defineProperty 这个方法
var obj = { ele: {}, num: 1 };
var tempAttr = "666";
Object.defineProperty(obj, "a", {
get() {
console.log("获取a属性");
return tempAttr;
},
set(val) {
console.log("设置a属性");
tempAttr = val;
},
});
console.log(obj.a);
obj.a = 1;
如果是Vue组件中使用data属性则data的值必须是Function,因为组件可能会多次调用为了保证每个组件在调用时data中的数据相互独立,所以必须用function返回一个全新的数据
Vue.component('countBox',{
data:{
num:1
},
template:`{{num}}`
})
new Vue({
template:` `,
}).$mount("#app");
如果在组件中使用object值,则会提示下方错误
下方代码说明vue实例对data的变量是引用赋值
如果设置的属性只做展示不需要响应可以使用
Object.seal(obj)
或者
Object.freeze(obj)
把数据冻结起来,vue就不会自动给递归设置setter/getter了
props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。
Vue.component('props-demo-simple', {
props: ['size', 'myMessage']
})
Vue.component('props-demo-simple', {
props: {
// 检测类型
height: Number,
// 检测类型 + 其他验证
age: {
type: Number,
default: 0,
required: true,
validator: function (value) {
return value >= 0
}
}
}
})
使用时,直接使用标签使用
上面是全局注册
如果要局部注册的话
new Vue({
components:{
mycomponent:{
props:['title1'],
template:`{{title1}}`
}
},
template: ` `,
}).$mount("#app");
创建实例时传递 props。主要作用是方便测试。
new Vue({
props:['title'],
propsData:{
title:"内容"
},
template: `{{title}}`,
}).$mount("#app");
只用于 new 创建的实例中
new Vue({
components:{
mycomponent:{
props:['title1'],
propsData:{
title1:"111111111111111111"
},
template:`{{title1}}`
}
},
template: ` `,
}).$mount("#app");
如果不过在经过new的vue实例中使用会有下方警告
计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例
注意如果你为一个计算属性使用了箭头函数,则 this 不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。
new Vue({
data() {
return {
num1: 4,
num2: 5
}
},
computed: {
calcResult() {
return this.num1 * this.num2
}
},
template: ` {{calcResult}}`,
}).$mount("#app");
页面上展示计算后的结果20
如果使用{ [key: string]: { get: Function, set: Function } } 时对computed中的属性赋值时会执行set方法,获取值的时候会执行get方法
new Vue({
data() {
return {
num1: 4,
num2: 5
}
},
computed: {
calcResult: {
get() {
return this.num1 * this.num2
},
set(val) {
this.num1 = val
}
}
},
template: ` {{calcResult}}`,
}).$mount("#app");
computed对返回的结果具有缓存作用,如果其中引用的data属性没有发生变化那么下次在读取的时候会直接取之前返回的值,下方设置定时器后观察返回的打印的结果可知
new Vue({
data() {
return {
num: 1
}
},
computed: {
calcResult() {
console.log(this.num)
return new Date()
}
},
mounted() {
setInterval(() => {
console.log(this.calcResult)
}, 500)
},
template: ` {{calcResult}}`,
}).$mount("#app");
methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为 Vue 实例。
主要用来监听data的数据变化,数据变化时会自动触发绑定的监听方法,下方是几种传值类型
data() {
return {
num: 1
}
},
[key: string]: string
watch: {
num: "watchNum"
},
methods: {
watchNum(val, oldVal) {
console.log(val, oldVal)
}
},
[key: string]: Function
watch:{
num(val,newVal){
console.log(val,newVal)
}
},
[key: string]: Object
watch: {
num: {
immediate: true,
deep: true,
handler(val, oldVal) {
console.log(val, oldVal)
}
}
},
[key: string]: Array
watch: {
num: [{
immediate: true,
deep: true,
handler(val, oldVal) {
console.log(val, oldVal)
}
},{
handler:"watchNum"
},
"watchNum1"
]
},
methods: {
watchNum(val, oldVal) {
console.log("function")
},
watchNum1(val, oldVal) {
console.log("function1")
}
},
生命周期是vue实例从初始化-》挂载-》更新数据和视图-》激活以及隐藏-》销毁的过程
每个过程发生时,都会触发对应的钩子函数。
生命周期函数包含下面这几种
在实例初始化之后,进行数据侦听和事件/侦听器的配置之前同步调用,此时this可以获取到vue实例,但是无法调用和获取vue中的data和methods中的属性和方法
数据侦听和事件/侦听器的配置之后,vue实例挂载到dom之前调用,此时可以通过this访问vue实例中的一些属性,但是无法通过ref获取dom元素
beforeMount() {
console.log("beforeMount")
},
mounted() {
console.log("mounted")
},
render(h) {
console.log("render")
return h("div", {}, "我是个div")
}
在可以看出来这个生命周期函数是在vue实例上属性成功之后,render函数调用之前触发的
在render函数执行后,vue实例中的dom成功挂载到指定元素上时触发,此时可以用通过ref获取真实的dom元素,但不能保证所有子组件也挂载成功,可以用$nextTick确保可以正常获取和操作子元素
this.$nextTick(() => {})
当有被监听的数据发生变化时并且在dom元素更新之前触发
当有被监听的数据发生变化时并且在dom元素更新之后触发,此时可以获取最新状态的dom元素
beforeUpdate() {
console.log('beforeUpdate')
console.log(this.$refs.myDiv.innerText)
},
updated() {
console.log('updated')
console.log(this.$refs.myDiv.innerText)
},
render(h) {
console.log("render")
return h("div", {
ref: "myDiv",
on: {
click: () => {
this.num++
}
}
}, `${this.num}`)
}
被 keep-alive 缓存的组件激活时调用
被 keep-alive 缓存的组件失活时调用。
keep-alive:在组件进行切换时,把失活的组件缓存起来
实例销毁之前调用。在这一步,实例仍然完全可用。可以通过this使用vue里的属性,也可以获取dom元素
实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
这里我们为全局挂载一个组件,根据打印的结果可以知道此时可以读取vue实例中的属性,但无法获取真实的dom元素
Vue.component("customDiv", {
data() {
return {
name: "我是待销毁的div"
}
},
beforeDestroy(){
console.log(this.name)
console.log(this.$refs)
},
destroyed() {
console.log(this.name)
console.log(this.$refs)
},
template: `{{name}}`,
});
....
render(h) {
return h("div", {
ref: "myDiv",
on: {
click: () => {
this.num++
}
}
}, [
`${this.num}`,
this.num < 2 ? h("customDiv") : ""
])
}
....
Vue生命周期流程图
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。
接下来我们来看一下钩子函数的参数 (即 el、binding、vnode 和 oldVnode)。
指令钩子函数会被传入以下参数:
下方自定义一个指令
Vue.directive('pin', {
inserted(el, binding, vnode,oldVnode){
console.log(el, binding)
},
})
new Vue({
data() {
return {
num: 1
}
},
template: `{{num}}`,
}).$mount("#app");
此时打印结果中没有oldValue
Vue.directive('pin', {
update(el, binding, vnode,oldVnode){
console.log(el, binding)
},
})
new Vue({
data() {
return {
num: 1
}
},
computed:{
args(){
return 'custom' + this.num
}
},
template: `{{num}}`,
}).$mount("#app");
如果绑定的内容更新的话就会有old数据
Vue.directive('focus', {
inserted(el, binding, vnode,oldVnode){
el.focus && el.focus()
},
})
new Vue({
template: `
`,
}).$mount("#app");
const state = Vue.observable({
permissions: ['add', 'edit', 'delete']
})
function checkPermission(permission) {
let count = permission.length
return state.permissions.filter(ele => permission.includes(ele)).length == count
}
Vue.directive('permission', {
inserted(el, binding, vnode, oldVnode) {
var permission = binding.value
var hasPermission = checkPermission(permission)
if (!hasPermission) {
el.parentNode.removeChild(el)
}
},
})
new Vue({
template: `
`,
}).$mount("#app");