横冲直撞vue(第四篇):v-model、指令系统总结、指令系统示例轮播图实现、指令系统示例跑马灯效果实现、在vue中使用样式的方式
v-model
指令在表单 <input>
、<textarea>
及 <select>
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
尽管有些神奇,但v-model
本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
v-model
在内部为不同的输入元素使用不同的属性并抛出不同的事件:
-
text 和 textarea 元素使用
value
属性和input
事件; -
checkbox 和 radio 使用
checked
属性和change
事件; -
select 字段将
value
作为 prop 并将change
作为事件。
vue的核心:声明式的指令和数据的双向绑定。
什么是数据的双向绑定?另外,大家一定要知道vue的设计模式:MVVM
M是Model的简写,V是View的简写,VM就是ViewModel。
单向绑定和双向绑定的区别?
单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新。
有单向绑定,就有双向绑定。
如果用户更新了View,Model的数据也自动被更新了,这种情况就是双向绑定。
什么情况下用户可以更新View呢?填写表单就是一个最直接的例子。当用户填写表单时,View的状态就被更新了,如果此时MVVM框架可以自动更新Model的状态,那就相当于我们把Model和View做了双向绑定。
其实单项数据也有双向绑定的意思,不过页面变动后数据的变化不会发生自动更新。
可以这样认为:双向数据绑定=单向数据绑定+UI事件监听。
先看个vue中双向数据绑定的例子:
<body> <div id="app"> <input type="text" v-model="msg"> <p>{{msg}}</p> </div> <script src="./lib/vue.js"></script> <script> var app = new Vue({ el:'#app', data :{ msg:'' } }) </script> </body>
页面效果如下
效果显示,当我们在input输入框中输入内容的时候,下面p标签同步显示内容。这就是最典型的双向数据绑定的例子。vue里使用v-model实现此想法。
浅析理解v-model实现过程
<body> <div id="app"> <!-- v-model这个指令很好理解,其实它就是一个语法糖 (甜甜的) 它是oninput事件和绑定value的实现 --> <input type="text" :value = 'text' @input = 'valueChange'> <h3>{{ text }}</h3> </div> <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> new Vue({ el:"#app", template:``, data(){ return { text:'hello' } }, methods:{ valueChange(event){ console.log(event.target.value); this.text = event.target.value } } }); </script> </body>
分析:v-mode指令是v-bind:vlaue 和v-on:input的结合体。针对input标签使用v-bind绑定value属性,使得input标签实时接收data的数据驱动,h3标签直接采用模板插值法,由data直接驱动,这是model对view
的单向绑定。
针对input标签绑定valuechange,数值变动事件,当input的数值发生变动时,由valueChange函数针对this.text的数值进行处理,这是view对model的单向绑定。由此构成了双向绑定。
用v-model实现简易计算器
<body> <div id="app"> <input type="text" v-model='num1'> <select v-model='opt'> <option value="+">+</option> <option value="-">-</option> <option value="*">*</option> <option value="/">/</option> </select> <input type="text" v-model='num2'> <button value='=' @click='calc'>=</button> <input type="text" v-model='res'> </div> <script src="./lib/vue.js"></script> <script> var app = new Vue({ el:'#app', data :{ num1:0, num2:0, res:0, opt:'+' }, methods: { calc(){ var calcStr = 'parseInt(this.num1)'+ this.opt + 'parseInt(this.num2)'; this.res = eval(calcStr); } } }) </script> </body>
二、指令系统总结
1、注意v-bind和v-on的简写
v-bind的简便写法,可以直接用 : 替代:
<img :src="imgSrc" :title="time"> <==对应==> <img v-bind:src="imgSrc" v-bind:title="time">
v-on的简便写法,可以直接用 @ 替代:
<button @click = "clickHandler">切换</button> <==对应==> <button v-on:click="clickHandler">切换</button>
2、对页面的dom进行赋值的运算
v-test、v-html、{{}}都是对页面的dom进行赋值,相当于js中的 innnerText 和 innerHTML。
3、对页面的dom进行条件渲染
(1)v-if的内在过程
v-if = 'true': <!--创建--> var oP = document.createElement('p'); oDiv.appendChild(op); v-if= 'false': <!--销毁--> oDiv.removeChild(op);`
(2)v-show的内在过程
v-show = 'true': oDiv.style.display = 'block'; v-show = 'false': oDiv.style.display = 'none'
(3)v-bind内在过程
v-bind:class: oDiv.className += ' active'
4、v-if与v-show的区别
实现方式区别:v-if是根据后面数据的真假值判断直接从Dom树上删除或重建元素节点;v-show只是在修改元素的css样式,也就是display的属性值,元素始终在Dom树上。
编译过程区别:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件; v-show只是简单的基于css切换。
编译条件区别:v-if是惰性的,如果初始条件为假,则什么也不做,只有在条件第一次变为真时才开始局部编译; v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素始终被保留。
性能消耗区别:v-if有更高的切换消耗,不适合做频繁的切换; v-show有更高的初始渲染消耗,适合做频繁的额切换。
5、vue的思想
vue是渐进式的JavaScript框架。大多数人觉得做加法比做减法简单。
vue这个框架将做减法的事情(困难的部分)都帮忙做了,人们只需要简单的部分就能实现复杂的dom操作。
三、指令系统之轮播图实现
1、轮播图简单示例
<style type="text/css"> ul{ list-style: none; overflow: hidden; width: 400px; } ul li{ float: left; width: 100px; height: 40px; line-height: 40px; background-color: purple; color: #fff; text-align: center; } ul li.active{ background-color: green; } </style> </head> <body> <div id="slider"> <img :src='currentImgSrc' alt=""> <ul> <li v-for = '(item,index) in imgArr' :class="{active:currentIndex==index}" @click='clickHandler(index)'> {{ index +1 }} </li> </ul> </div> <script src="./lib/vue.js"></script> <script type="text/javascript"> // 数据驱动视图 var imgArr = [ {id:1,imgSrc:'./images/1.jpg'}, {id:2,imgSrc:'./images/2.jpg'}, {id:3,imgSrc:'./images/3.jpg'}, {id:4,imgSrc:'./images/4.jpg'} ]; new Vue({ el:'#slider', template:``, data(){ return{ imgArr:imgArr, currentIndex:0, currentImgSrc:'./images/1.jpg' } }, methods:{ clickHandler(index){ this.currentIndex = index; this.currentImgSrc = this.imgArr[index].imgSrc; } } }); </script> </body>
页面效果如下
2、轮播图进阶
(1)增加点击下一张
<style type="text/css"> ul{ list-style: none; overflow: hidden; width: 400px; } ul li{ float: left; width: 100px; height: 40px; line-height: 40px; background-color: purple; color: #fff; text-align: center; } ul li.active{ background-color: green; } </style> </head> <body> <div id="slider"> <img :src='currentImgSrc' alt=""> <ul> <li v-for = '(item,index) in imgArr' :class="{active:currentIndex==index}" @click='clickHandler(index)'> {{ index +1 }} </li> </ul> <button class="btn" @click='nextImg'>下一张</button> </div> <script src="./lib/vue.js"></script> <script type="text/javascript"> // 数据驱动视图 var imgArr = [ {id:1,imgSrc:'./images/1.jpg'}, {id:2,imgSrc:'./images/2.jpg'}, {id:3,imgSrc:'./images/3.jpg'}, {id:4,imgSrc:'./images/4.jpg'} ]; new Vue({ el:'#slider', template:``, data(){ return{ imgArr:imgArr, currentIndex:0, currentImgSrc:'./images/1.jpg' } }, methods:{ clickHandler(index){ this.currentIndex = index; this.currentImgSrc = this.imgArr[index].imgSrc; }, nextImg(){ if(this.currentIndex==this.imgArr.length-1){ this.currentIndex = -1; } this.currentIndex++; this.currentImgSrc = this.imgArr[this.currentIndex].imgSrc; } } }); </script> </body>
页面显示效果
(2)实例生命周期钩子
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
比如 created
钩子可以用来在一个实例被创建之后执行代码:
<style type="text/css"> ul{ list-style: none; overflow: hidden; width: 400px; } ul li{ float: left; width: 100px; height: 40px; line-height: 40px; background-color: purple; color: #fff; text-align: center; } ul li.active{ background-color: green; } </style> </head> <body> <div id="slider"> <img :src='currentImgSrc' alt=""> <ul> <li v-for = '(item,index) in imgArr' :class="{active:currentIndex==index}" @click='clickHandler(index)'> {{ index +1 }} </li> </ul> <button class="btn" @click='nextImg'>下一张</button> </div> <script src="./lib/vue.js"></script> <script type="text/javascript"> // 数据驱动视图 var imgArr = [ {id:1,imgSrc:'./images/1.jpg'}, {id:2,imgSrc:'./images/2.jpg'}, {id:3,imgSrc:'./images/3.jpg'}, {id:4,imgSrc:'./images/4.jpg'} ]; new Vue({ el:'#slider', template:``, data(){ return{ imgArr:imgArr, currentIndex:0, currentImgSrc:'./images/1.jpg' } }, created(){ // 生命周期方法 setInterval(this.nextImg, 2000) // setInterval()方法可按照指定的周期(以毫秒计)来调用函数或计算表达 }, methods:{ clickHandler(index){ this.currentIndex = index; this.currentImgSrc = this.imgArr[index].imgSrc; }, nextImg(){ if(this.currentIndex==this.imgArr.length-1){ this.currentIndex = -1; } this.currentIndex++; this.currentImgSrc = this.imgArr[this.currentIndex].imgSrc; } } }); </script> </body>
设置created生命周期方法后,页面上自动轮播图片
也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted
、updated
和 destroyed
。生命周期钩子的 this
上下文指向调用它的 Vue 实例。
created方法还可以用来获取cookie和session。
(3)鼠标 移入/移出 时 停止/开启 定时器
<style type="text/css"> ul{ list-style: none; overflow: hidden; width: 400px; } ul li{ float: left; width: 100px; height: 40px; line-height: 40px; background-color: purple; color: #fff; text-align: center; } ul li.active{ background-color: green; } </style> </head> <body> <div id="slider"> <img :src='currentImgSrc' alt="" @mouseover='stoptimer' @mouseleave='opentimer'> <ul> <li v-for = '(item,index) in imgArr' :class="{active:currentIndex==index}" @click='clickHandler(index)'> {{ index +1 }} </li> </ul> <button class="btn" @click='nextImg'>下一张</button> </div> <script src="./lib/vue.js"></script> <script type="text/javascript"> // 数据驱动视图 var imgArr = [ {id:1,imgSrc:'./images/1.jpg'}, {id:2,imgSrc:'./images/2.jpg'}, {id:3,imgSrc:'./images/3.jpg'}, {id:4,imgSrc:'./images/4.jpg'} ]; new Vue({ el:'#slider', template:``, data(){ return{ imgArr:imgArr, currentIndex:0, currentImgSrc:'./images/1.jpg', timer:null } }, created(){ // 生命周期方法 this.timer = setInterval(this.nextImg, 500) // setInterval()方法可按照指定的周期(以毫秒计)来调用函数或计算表达 }, methods:{ clickHandler(index){ this.currentIndex = index; this.currentImgSrc = this.imgArr[index].imgSrc; }, nextImg(){ if(this.currentIndex==this.imgArr.length-1){ this.currentIndex = -1; } this.currentIndex++; this.currentImgSrc = this.imgArr[this.currentIndex].imgSrc; }, stoptimer(){ clearInterval(this.timer); //停止定时器 }, opentimer(){ this.timer = setInterval(this.nextImg, 500) //开启定时器 } } }); </script> </body>
页面显示效果
注意开启定时器时不能直接调用this.created生命周期方法,必须直接开启定时器。
四、指令系统之跑马灯效果实现
<body> <!-- 2. 创建一个要控制的区域 --> <div id="app"> <input type="button" value="浪起来" @click="lang"> <input type="button" value="低调" @click="stop"> <h4>{{ msg }}</h4> </div> <script> // 注意:在 VM实例中,如果想要获取 data 上的数据,或者 想要调用 methods 中的 方法,必须通过 this.数据属性名 或 this.方法名 来进行访问,这里的this,就表示 我们 new 出来的 VM 实例对象 var vm = new Vue({ el: '#app', data: { msg: '猥琐发育,别浪~~!', intervalId: null // 在data上定义 定时器Id }, methods: { lang() { // console.log(this.msg) // 获取到头的第一个字符 // this if (this.intervalId != null) return; this.intervalId = setInterval(() => { var start = this.msg.substring(0, 1) // 获取到 后面的所有字符 var end = this.msg.substring(1) // 重新拼接得到新的字符串,并赋值给 this.msg this.msg = end + start }, 400) // 注意: VM实例,会监听自己身上 data 中所有数据的改变,只要数据一发生变化,就会自动把 最新的数据,从data 上同步到页面中去;【好处:程序员只需要关心数据,不需要考虑如何重新渲染DOM页面】 }, stop() { // 停止定时器 clearInterval(this.intervalId) // 每当清除了定时器之后,需要重新把 intervalId 置为 null this.intervalId = null; } } }) // 分析: // 1. 给 【浪起来】 按钮,绑定一个点击事件 v-on @ // 2. 在按钮的事件处理函数中,写相关的业务逻辑代码:拿到 msg 字符串,然后 调用 字符串的 substring 来进行字符串的截取操作,把 第一个字符截取出来,放到最后一个位置即可; // 3. 为了实现点击下按钮,自动截取的功能,需要把 2 步骤中的代码,放到一个定时器中去; </script> </body>
页面显示效果
五、在Vue中使用样式(v-bind补充)
使用class样式
-
数组
<h1 :class="['red', 'thin']">这是一个邪恶的H1</h1>
-
数组中使用三元表达式
<h1 :class="['red', 'thin', isactive?'active':'']">这是一个邪恶的H1</h1>
-
数组中嵌套对象
<h1 :class="['red', 'thin', {'active': isactive}]">这是一个邪恶的H1</h1>
-
直接使用对象
<h1 :class="{red:true, italic:true, active:true, thin:true}">这是一个邪恶的H1</h1>
使用内联样式
-
直接在元素上通过
:style
的形式,书写样式对象
<h1 :style="{color: 'red', 'font-size': '40px'}">这是一个善良的H1</h1>
-
将样式对象,定义到
data
中,并直接引用到:style
中
-
在data上定义样式:
data: { h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' } }
-
在元素中,通过属性绑定的形式,将样式对象应用到元素中:
<h1 :style="h1StyleObj">这是一个善良的H1</h1>
-
在
:style
中通过数组,引用多个data
上的样式对象
-
在data上定义样式:
data: { h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' }, h1StyleObj2: { fontStyle: 'italic' } }
-
在元素中,通过属性绑定的形式,将样式对象应用到元素中:
<h1 :style="[h1StyleObj, h1StyleObj2]">这是一个善良的H1</h1>
参考资料
[1]https://www.cnblogs.com/crazymagic/p/9726673.html
[2]
posted on 2020-04-10 23:32 Nicholas-- 阅读(351) 评论(0) 编辑 收藏 举报