vue是一个前端JS库,用MVVM模式实现;
主要作用是动态构建用户界面;
重要技术包括:模版与数据绑定(angular),组件与虚拟DOM(react),其中,模版就是HTML中套JS。表现形式就是:大括号表达式或者绑定指令。即模版里面的JS从哪读数据呢,则就需要从data里面读数据。实现静态页面变成动态页面,则就需要用到数据绑定技术。数据绑定分为两个方面,一个是页面能根据数据来显示,另一个最重要,即:只要我更新了数据,则页面就会发生变化。或者说我想让页面发生变化,那我就去更新数据。
而MVVM则是:M是model,即模型,也就是个数据对象,包含数据的对象,而包含的数据对象在VUE中就是data
V是view,即视图,在VUE中对应的就是模版页面,模版页面最终经过编译以后,生成的就是真实的DOM,当然在这个中间也会产生一些虚拟的DOM,最终显示给用户,展现在页面上
VM是ViewModel,即视图模型,在VUE对应的就是VUE的实例,不是VUE,是VUE的实例,这点需要搞清楚。而在VM中又包括两个东西,其中VM是 View 和 Model 之间的桥梁,用户在意的是视图,但是我们在编码操作的时候往往不是直接编码操作视图,而是去操作数据,然后让视图自动发生变化,或者说我在页面中输入一个内容,而内容能不能自动跑到数据里面去呢?也就是Model中。这都要靠VM,也就是ViewModel,即VUE的实例,简称VM。
在VM中,有两个方面,一个是Data Bindings ,翻译过来叫数据绑定,它能够让数据data从model中流向视图view中;另一个方面,是有DOM监听,即DOM Listeners,利用DOM监听,来让数据,从页面View流向Model中去,这主要体现在 v-model 指令上,即在输入框内输入一些内容,而此时输入框有 v-model 的话,则数据会自动跑到Model的data里面去。
为什么能跑到Model中去呢?
因为在输入框input上面绑定了一个监听,这个监听就是输入改变的监听,绑定监听则必然指定了回调函数,也就是说,当输入改变的时候,这个回调函数在干什么呢?两个事情,第一:读取最新输入的值;第二步,将最新的值保存到对应的data属性上。而一旦保存到data属性上,下面就是数据绑定的流程了, 就没DOM监听什么事了。也就是说,在DOM事件监听这条线上,只负责绑定事件监听,并且在事件监听的回调函数中,将最新的数据保存到data上去。这就是双向数据绑定的过程,也就是数据有两个方向的流向。
new Vue({
el: '#app',
components:{ APP },
//template的作用:若有这个属性,则把 template: ' ' 当成一个模版去渲染解析, 而这个模版里面包含一个 App 的组件标签。其中在Vue中,定义一个组件以后,必须要去注册,如果不注册是不知道组件标签名的。而配置components就是用来注册组件的。
//components的完整写法是:components: {App : App},其中右边是组件,而左边则是给它起的名称,而这名称就是组件的标签名
template: ' '
})
beforeCreate
:创建实例之前执行的钩子函数created
:创建实例之后执行的钩子函数el
选项,如果有就可以执行编译模版,也就是把data
对象里面的数据和Vue
语法声明的模版编译成浏览器可读的html
。如果没有el
,那就用vm.$mount()
去挂载模版beforeMount
:将编译完成的html
挂载到对应虚拟DOM
时触发的钩子函数html
替换掉el
属性所指向的DOM
mounted
:编译好的html
挂载到页面完成后执行的事件钩子函数DOM
beforeUpdate
:更新数据之前执行的钩子函数updated
:更新数据之后执行的钩子函数beforeDestroy
:实例销毁之前执行的钩子函数destroyed
:实例销毁完成后执行的钩子函数runtime-compiler
中,用App
的步骤:
App
做一个注册template
中使用这个组件runtime-only
中,用App
的方式:使用render
属性,名称为渲染
,是个函数,即其右边是一个箭头函数Vue的运行过程:
template
保存到Vue
中的options
中template
进行解析parse
,把template
解析成ast
,也即是抽象语法树(abstract syntax tree
)compile
编译,编译成render
函数,其中render
函数的核心是用了createElement
方法,即创建一个元素render
函数把template
最终翻译成虚拟DOM
DOM
渲染成真实的DOM
,并显示在页面上总结:runtime-only
的性能更高
,代码更少
注意:vue-loader
是用来加载Vue
文件,而解析Vue
文件则是用vue-template-compiler
,也就是将Vue
中的template
解析成render
函数。
用法:当你修改了data的值以后,如果想马上获取dom元素的值,是不获取不到更新后的值,所以就需要使用$nextTick这个回调,它是在下一次 DOM 更新循环之后,再去执行的回调函数。也就是让修改后的data值重新渲染更新到dom元素之后在获取。
用法:keep-alive
标签用于包裹router-view
标签,就可以保对应的证组件不会被频繁的销毁或者创建,即
<keep-alive>
<router-view>
<keep-alive>
属性之exclude
,作用是排除一些组件,即
//注意:这里不用加空格,其次,Profile,User是组件里面的name属性值
<keep-alive exclude = "Profile,User">
<router-view>
<keep-alive>
正确写法:
{
path: '',
redirect: '/home'
},
错误示范:
{
path: '',
redirect: Home
},
//定义全局过滤器
Vue.filter('toUpper', function(value) {
return value.toUpperCase()
})
//使用:既可以在 双花括号插值 中使用,又可以用在 v-bind 表达式
<h2>{{message | toUpper}}</h2>
new Vue({
el: '#text',
data: {
message: 'fjsalfjla'
},
filters: {
toUpper: (value) => {
return value + '这又是一段拼接的字符串'
}
}
})
//使用:当全局过滤器和局部过滤器重名时,会采用局部过滤器。
<h2>{{message | toUpper}}</h2>
作用:把要显示的数据进行格式化处理后再显示。即通过定义过滤器,实现一些常见的文本格式化
好处:因为定义的是全局过滤器,所以定义好之后可以全局使用,还可以反复使用。
注意:当全局过滤器和局部过滤器重名时,会采用局部过滤器。
所有指令的共性:所有指令都是用来操作指令属性所在的标签对象的,不管是内置的还是自定义的
1). 注册全局指令
//全局指令的 directive 没有 s
Vue.directive('my-directive', function(el, binding){
/*
* el:这是个标签,是 指令属性 所在的 标签对象
* binding:包含一些指令相关属性数据(value)的对象
* 自定义指令和过滤器很像,第一个参数是指令的名字,第二个参数是个函数,作用是用来解析指令的
*/
el.innerHTML = binding.value.toUpperCase()
})
2). 注册局部指令
//局部指令的 directive 有 s
directives : {
'my-directive' : function(el, binding) {
el.innerHTML = binding.value.toLowerCase()
}
//或者把 function 去掉
'my-directive'(el, binding) {
el.innerHTML = binding.value.toLowerCase()
}
}
Vue.directive('upper-text', function (el, binding) {
//toUpperCase():把value的值全部转化为大写
el.textContent = binding.value.toUpperCase()
})
new Vue({
el: '#demo',
data: {
message: 'HA HA HA'
},
directives: { // 局部指令, 只能当前vm有效
'lower-text'(el, binding){
//toLowerCase():把value的值全部转化为小写
el.innerText = binding.value.toLowerCase()
}
}
})
new Vue({
el: '#demo2',
data: {
message: 'HE HE HE HE'
}
})
//结构部分
<div id="demo">
<p v-upper-text="message"></p>
<p v-lower-text="message"></p>
</div>
<div id="demo2">
<p v-upper-text="message"></p>
<p v-lower-text="message"></p>
</div>
局部指令和全局指令的区别:局部指令只对当前Vue实例有效,而全局指令对所有Vue的实例有效
指令v-text是给 p 标签指定标签体文本,至于这个 p 标签里面以前有没有值,根本不关心,因为就算有值也不会显示,即拥有了(娶了)v-text指令以后,以后的全部重心都是v-text里面的值;而插值语法只是 p 这个文本标签节点的一个部分而已,跟(娶了小妾一样,即不是全部),也就是说用插值语法,则 p 标签里面还可以放其他内容,但是用了指令v-text,那么 p 标签里面,你就啥也不能放了。
v-text
和 v-html
的区别:
一个解析文本,一个解析HTML
get
是用来动态计算来产生值,而set
是监视这个属性值的变化Vue
控制的所有回调函数this
都是vm
/组件对象view
模版中,访问的变量或者表达式的值,访问的都是vm
(Vue的实例)的属性,然后这些属性对应的get
方法,可以去访问data
对应的属性值。computed: { // 计算属性
fullName1() { // 相当于getter
console.log('fullName1()')
return this.firstName + '-' + this.lastName
},
fullName3: {
get() {
return this.firstName + '-' + this.lastName
},
//计算属性set调用时机:当前属性的值发生改变
set(value) {
console.log('fullName3 set()', value)
const names = value.split('-')
this.firstName = names[0]
this.lastName = names[1]
}
}
},
// 监视
watch: {
// 监视firstName
firstName(value) { // firstName的值变化了
this.fullName2 = value + '-' + this.lastName
}
}
// 监视lastName
vm.$watch('lastName', function(value) { // lastName的值变化了
console.log('lastName', value)
this.fullName2 = this.firstName + '-' + value
})
通信(至少有两个组件):通信是有方向的,假设A向B通信,即A向B中传递一个数据,注意这个数据是一般是属性,而不是函数,即是非函数数据,是可以显示的数据。当然了,也可以是B向A通信。总结:通信就是传递数据;通信有方向。
组件有组件之间的关系:父子关系,祖孙关系,兄弟关系或者其他(表侄关系)。
Props通信:通信双方最好是父子关系,可以是父向子,也可以是子向父,即可以是双向的。利用props什么时候是父向子通信呢?答:传递一般属性时,一般属性是指属性值不是函数的时候称为一般属性。如果想用props来向子向父通信呢?答:用传递函数的方法或者ref。
事件:1,绑定监听 2,触发(分发)事件
语法:
this.$emit('myevent',value)
其中myEvent是事件名称,value是需要传递的值,当然这个值也可以不写。
调用语法:
<my-component v-on:myevent="doSomething">my-component>
注意:这个绑定监听的操作必然发生在my-component组件所在的父组件里面。因为只有在父组件里面才有这个标签。有了标签以后,才能通过属性绑定自定义监听。
也就是绑定监听操作的代码要在父组件里面执行,而this.$emit('myevent',value)
才在子组件里面执行。
vm.$on(event,callback)
可以在父组件里面给子组件对象绑定监听,而在子组件内部分发事件,而事件监听的回调函数是定义在父组件身上的。
绑定监听的一方是收数据的,因为监听就有回调,回调就有形参,形参就能收数据
A向B发数据,则在A中写触发事件的代码,即用emit
,而在B中写绑定监听的代码,即on
用法:可以实现任意组件任意关系之间传递数据
核心:new一个bus作为总线对象,即var bus = new Vue();
或者在Vue的原型上做文章,即Vue.prototype.$globalEventBus = new Vue()
假设是A向B发信息,也就是发数据,或者称为发消息,则A中写触发事件的代码,在B中写绑定监听的代码。
在A中,bus.$emit("事件名称","要传递的数据")
在B中,bus.$on("事件名称", "需要调用的函数")
,其中,"需要调用的函数"有两种写法,第一种是在B组件的methods
中写好该函数,然后用this.写好的函数
来完成该事件
第二种是直接写一个箭头函数出来,并且在箭头函数中处理传过来的数据