一,vue的核心属性
1,模板语法
1.1,插值语法
就是直接使用两对花括号接收实例传过来的值。如下面的 {{name}} ,这样就获取到了这个vue实例中的name属性的这个值
<div id="root"> <h1 id="c">hello {{name}}</h1> </div> < script type = "text/javascript" > new Vue({ //指定当前实例为哪个容器服务,id对应#,class对应. el: '#root', //data用于存储数据,只有el对应的容器可以使用 data: { name: 'zhenghuisheng' } }) </script>
1.2,指令语法
就是通过标签内部将实例的值就行一个引用,如做一个双向绑定,可以使用 v-bind 这个指令,同时这个指令也可以简写成 :bind 。除了这个v-bind,像其他的 v-if , v-model都是这个指令语法
<div id="root"> <a v-bind:href = "url">点击跳转百度</a> <a :href = "url">点击跳转百度</a> </div> < script type = "text/javascript" > new Vue({ //指定当前实例为哪个容器服务,id对应#,class对应. el: '#root', //data用于存储数据,只有el对应的容器可以使用 data: { url:'https://www.baidu.com/', } }) </script>
插值语法和指令语法的区别就是:插值语法往往是用于解析标签体中的内容,指令语法往往用于解析标签,比如说一些标签属性,标签体内容,绑定事件等。
2,数据绑定
数据绑定主要分为单向绑定和双向绑定。
2.1,单向绑定
单向绑定只能用于从vue实例流向页面,就是在修改了vue实例中的data值的时候,那么对应的容器中的值也会跟着改变,而修改容器中的值,vue实例中的值不改变。
单向数据绑定:<input type="text" v-bind:value = "name"><br/> 单向数据绑定简写:<input type="text" :value = "name"><br/>
2.2,双向绑定
不仅可以将值从vue实例流向容器,也可以将值从容器流向实例。就是当Vue实例中的值发生变化的时候,那么这个容器中的值也会发生改变,容器中的值发生改变那么就意味着页面上的值也会发生改变;反之亦然,页面上的值发生改变,那么vue实例上的值也会发生改变。
双向数据绑定:<input type="text" v-model:value = "name"><br/> 双向数据绑定简写:<input type="text" v-model = "name"><br/>
但是双向绑定一般都应用在表单元素上,如一些input,select等,即对应的元素一定要有一个value值。
3.mvvm模型
主要有View视图层,model模型层和ViewModel视图模型中间层这三层组成,
模型层用M来表示,主要对应Vue实例的data中的一些数据,如上述所说的一般的js对象。
视图主要是用V来表示,就是通过一些模板生成的页面
视图模型主要是通过 VM 来表示,主要是对应整个具体的Vue实例对象。在ViewModel里面,有一个Data Bindings数据绑定和DOM LIsteners监听器,数据绑定就是上面的单向绑定和双向绑定,监听器就是当数据发生变换的时候,单向绑定或者双向绑定里面需要进行相应的改变就是通过这个监听器来实现的。
如下段代码,这个div对应的就是view视图层,Vue实例中的 data 就是对应的model 模型层,整个 new 出来的Vue 实例就是VIewModel 视图模型层。
<div id="root"> <h1 id="c">hello {{name}}</h1> </div> < script type = "text/javascript" > new Vue({ //指定当前实例为哪个容器服务,id对应#,class对应. el: '#root', //data用于存储数据,只有el对应的容器可以使用 data: { name: 'zhenghuisheng' } }) </script>
主要是通过这个ModelView实现Model和View之间的连接。
4,数据代理
4.1,数据代理的基本使用
主要是通过这个 Object.defineProperty实现,通过这个方式来实现对象的代理,并且在该对象中设置属性和属性值。
let person = { name:'zhs', sex:'男' } //第一个参数:要代理的对象 //第二个参数:该对象中需要增加的属性 //第三个参数:该属性对应的值 Object.defineProperty(person,'age',{ value:'18' })
但是在输出对象中可以发现通过代理增加进来的属性其颜色值稍微比较浅,并且在这个被代理的person对象中,他的这个age属性值不能被枚举,如在遍历时,这个值不能获取到这个值。
当然也可以通过这个 enumerable 这个属性来控制是否可以使用这个枚举字段。这个字段的默认值为false,设置为true之后,这个枚举值外部就可以直接使用了。 同时还有这个writable属性,用于控制其值能否被修改,以及configurable属性,用于判断属性是否可以被删除。
Object.defineProperty(person,'age',{ value:'18', enumerable:true, writable:true, configurable:true })
也可以通过函数的方式来为这个对象的age属性赋值,并且这个对象的age的值可以获取局部变量中的值。
let number = 100; Object.defineProperty(person,'age',{ //当需要读取这个person的age属性时,get函数(getter)就会被调用 get:function(){ return number } //当需要设置这个person的age属性时,set函数(setter)就会被调用 set(value){ console.log('有人修改了属性,且值是',value ) number = value } })
4.2,数据代理在vue中使用
依旧是这个那么属性值,结合上面的setter和getter。就是当读取一个值的时候,会通过这个getter的动态代理方式将值从vue实例赋予页面中;当修改这个值的时候,也会调用这个setter的动态代理,将值修改之后存放到vue实例,vue实例的值做出相应的修改,然后又由于监听器发现这个值发生该变化,然后又会通过双向绑定将被修改的值又回显到页面中。
<div id="root"> <h1 id="c">hello {{name}}</h1> </div> < script type = "text/javascript" > new Vue({ el: '#root', data: { name: 'zhenghuisheng' } }) </script>
并且,实例中的 data 值,和这个 _data值一样,因此有了这个动态代理之后,就是将需要通过 {{vm._data.name}}获取值的方式,直接转换成简单的方式了。
4.3,数据代理总结
其实这个数据代理的底层就有那么一点像JDK的动态代理,就是通过实现一个接口,然后将要被代理的对象的值获取出来,然后做一个动态增强,就是在原来的值的基础上,对值进行一个内部的读写操作。这个vue的代理原理也是这样的,通过这个 Object.defineProperty 方法将所有属性添加到这个vm上,然后通过setter和getter去操作里面的属性。
其主要原理就是通过vm对象代理出vue实例的data对象,然后通过这个vm对象来操作里面的属性。
5,事件
5.1,事件处理
就是通过v-click()去调用一个函数,如一个按钮的点击事件,在容器中的配置如下。
//在容器中新增一个按钮,不传参,内部默认传一个event事件 <button v-click = "show">点我提示信息</button> //传参,需要携带$event,参数位置随意 <button v-click = "show($event,a)">点我提示信息</button>
在实例中的配置如下,
new Vue({ //methods:{ show(event){}} //不加参数 methods:{ show(event,a){...}} //不加参数 })
这个指令也可以直接使用简写 @click() 。在vue实例中,methods里面的方法不会做数据代理,而这个data中的数据会做数据代理。
5.2,事件修饰符
Vue中总共有六种事件修饰符,主要有prevent,stop,once,capture,self,passive这六种,其中前面三种比较常用。
5.2.1,prevent
表示阻止默认事件。如下,在一个超链接中写一个弹窗,然后点击完弹窗之后让他不进行一个超链接的跳转
<div id="root"> <a href = "www.baidu.com" @click.prevent = "toBaiDu">点击跳转到百度</a> </div> < script type = "text/javascript" > new Vue({ el: '#root', methods:{ toBaiDu(e){ alert("点击完才能跳转百度..."); } } }) </script>
5.2.2,stop
表示阻止事件冒泡,比如说一个嵌套的容器都绑定了一个点击事件,那么这个内部的容器触发完这个事件之后,外部的这个容器也会触发一次。如下面有一个div和一个button,点击这个按钮之后,两个容器都会触发这个事件,都会弹窗出这个东西,但是加了这个stop之后,那么就不会有第二次的弹窗了。
<div id="root" @click = "toBaiDu"> <button @click.stop = "toBaiDu">点我</button> </div> < script type = "text/javascript" > new Vue({ el: '#root', methods:{ toBaiDu(e){ alert("点击完才能跳转百度..."); } } }) </script>
5.2.3,once
表示事件只触发一次,如在刚进入一个系统的页面时会有一个欢迎的小弹窗,弹完这一次之后就再也不会出现。
<div id="root" @click = "toBaiDu"> <button @click.once = "toBaiDu">点我</button> </div> ...
5.2.4,capture
表示事件的捕获模式。如下在两个嵌套的容器中,同时都绑定了这个showMsg的这个事件,那么在点击这个box2的时候box1也会受到影响。在整个过程中,会经历一个捕获阶段和一个冒泡阶段,捕获阶段就是从1到2,也就是从外到内;冒泡阶段才是真正处理事件的阶段,冒泡顺序就是从2到1,那么处理事件阶段也是从2到1。要是想解决这种先捕获先处理事件,可以直接在box1上面的事件使用 @click.capture ,这样就能在捕获之后,立马将事件处理了。
<div class="box1" @click="showMsg(1)"> div1 <div class="box2" @click="showMsg(2)> div2 </div> </div>
5.2.5,self
表示只有event.target是当前操作的元素蔡触发事件。 如下这个div容器和button按钮都绑定了这个showInfo事件,在点击按钮之后也会从按钮冒泡到div容器。但是由于点击的是按钮,那么这个event.target的值始终是这个按钮,不会因为冒泡而发生改变,所以在添加这个.self之后,div容器发现这个event.target 的值不是div,那么也就不会触发这个事件了。这也是通过另一种思路来阻止冒泡。
<div class="box1" @click.self="showInfo"> <button @click="showInfo">点我提示信息</button> </div>
5.2.6,passive
表示事件的默认行为立即执行,无需等待事件回调执行完毕。 就是类似于异步操作,优先先响应可见的或者说是默认的操作,复杂的操作异步去完成。
<ul @wheel.passive="demo" class="list">
以上六种事件,也可以结合使用,如这个阻止默认事件和阻止冒泡结合使用
@click.prevent.stop="showInfo"
5.3,键盘事件
在键盘事件中,主要有keyDown和keyUp两种绑定事件,主要是通过这个@keydown和@keyup两种方式修饰。在vue中,有九个常用的别名,分别如下
回车 => enter 删除 => delete 退出 => esc 空格 => space 换行 => tab 上 => up 下 => down 左 => left 右 => right
然后就可以直接通过指令的方式,从而触发这个键盘事件。如下,在点击这个回车键的时候,就会触发这个事件。
@keyup.enter = "showInfo"
也可以直接通过键盘上面的名字作为后面的参数,如果有两个字母组成的,如CapsLock,那么需要将两个字母都变成小写,然后之间加一根横线,即写成caps-lock。
//先通过event.key 获取到键盘上面的名字 showInfo(event){ console.log(event.key); } //获取到名字之后将名字加入到这个@keyup. 的后面 @keyup.Enter = "showInfo"
键盘上也有五个比较特殊的键,分别是tab,ctrl,alt,shift,meta。tab键由于本身带有切换焦点的功能,因此这个tab键必须和这个keydown去结合使用;其余四个性质一样,最好也是配合着keydown去使用,可以正常的触发事件,如果配合这个keyup,那么除了按下本身这个键之外,还需要随机的按一个键,并且在这个随机键释放的时候事件才会被触发。