irpas技术客

Vue知识点唠嗑之数据驱动_vue 数据驱动_躲在车里的猫

未知 5509

Vue是一个以数据驱动的web前端框架。啥是数据驱动?以前写前端,最主要的就是jQuery大法,通过jQuery提供的定位DOM元素的方法直接操作DOM,这样的话,程序员在处理html页面的时候,既要考虑数据的格式和逻辑,又要考虑怎么使用DOM将数据渲染出来。不同水平的程序员渲染出来的页面速度层次不齐。而Vue就是将程序员从繁琐的DOM操作中释放出来,让程序员只需要关心数据就可以了,无需关心DOM怎么改,修改数据就可以自动修改对应的DOM。所以说,Vue是数据驱动的,所谓的数据驱动就是指只要改变变量,就可以改变DOM节点,程序员无需关注具体的DOM操作。

一个Vue的HelloWorld:

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-Type" charset="UTF-8"> <meta http-equiv="x-ua-compatiable" content="IE=edge"> <title>Hello</title> <script src="./vue.js"></script> </head> <body> <div id="app" v-text="greeting"></div> <script> // 新建一个Vue实例 new Vue({ el:"#app",// 渲染哪个标签 data:{ greeting: "Hello Vue" //只要把greeting修改了,对应的页面的字也会跟着改变 } }) </script> </body> </html>

为什么Vue可以通过监听数据的变化来实现DOM的改变?

主要是使用了ES5中的Object.defineProperty 方法。所以不支持ES5的浏览器是无法使用Vue的。

// myname的属性被拦截了 Object.defineProperty( obj, "myname", { get(){ console.log("get"); }, set(data){ console.log(data); console.log("set"); } } ) // 定义了get和set方法,当通过obj.myname方式获取到值时,会自动触发get方法。通过obj.myname对myname属性值修改时,会自动触发set方法。即通过get、set方法拦截取值、赋值操作。

以下是Vue官网的一幅图片:

Vue的主要思想就是虚拟DOM的概念,因为修改DOM比较慢,但是更新DOM会比较快。在数据发生变化之后,Vue会根据新数据重新生成一个虚拟DOM,与原DOM进行比较,并在原DOM上进行修改,从而实现了较为快速的更新DOM。

但是Vue在更新数据响应方面有一些是无法进行响应的,主要就是对数组和对象的变化。

1.接下来围绕数据驱动,说说具体在哪些方面有体现: 11.通过指令得到体现

首先要说的是,指令的后面都会被Vue解析为data里面的变量。

v-html通过此属性的值会进行HTML转义。

v-bind 之后,属性值就是js代码。v-bind:class = :class,v-bind可以省略。此外v-bind还有一种绑定的方法,就是:

data() { return { name:'title', message: 'HelloWorld!' } }, template: `<div :[name]="message" > {{ message }} </div>`

上述使用:[name]的方式是属性的动态绑定,此时name就不是字符串?,而是data中的name变量的值。

v-if 与 v-show:前者直接删除,后者不直接删除,只是加了display:none的属性

v-on:v-on:click="handleMyClicker",在methods中定义方法。可以省略为@click="handleMyClicker"

访问data中的数据,直接用this就可以。?v-once:DOM只渲染一次,data数据再改变也不会重新渲染DOM了

v-for:循环指令。一般为v-for="item in datalist"。对于这个指令需要注意的是in前面可以有两个参数,可以有三个参数。对于数组而言,可以有两个参数,即 v-for="(item,index) in datalist",item是指数组元素,index是指数组的元素索引,从0开始。item、index这两个可以随便写,Vue主要通过位置来判断哪个是值,哪个是索引。对于对象而言,就可以有三个参数了,如下:

有一个参数的情况: objects:[ {id:1,message:"a"}, {id:2,message:"b"}, {id:3,message:"c"}, {id:4,message:"d"}, ] 一个参数很简单,通过点的方式获取到对象里的值: <div v-for="item in objects"> {{ item.id }} -- {{ item.message }} </div> 两个参数: <div v-for="(item,data) in objects"> {{ item.id }} -- {{ item.message }} </div>

当然,索引和值在数组里面和在对象里面是不一样的。在数组里面索引是指数组元素的下标,但是在对象中则是键值。用v-for来遍历对象元素,如下:

<div id="app"> </div> <script> const app = Vue.createApp({ data(){ return { listObj: { firstName: 'Dell', lastName: 'Lee' } } }, template: ` <div v-for="(value, key, index) in listObj"> {{ value }} -- {{ key }} -- {{ index }} </div> ` }) app.$mount("#app") </script>

v-for后面的循环条件,可以有of,也可以用in

v-for="items in objArr" objArr为列表 v-for="items in obj" obj为对象 v-for="items of obj" obj为对象,不可用of来遍历 v-for="items of objArr" 对于数组而言,in和of都可以

v-for还可以在标签内指定一个key值,个人认为这个key值的设置,主要作用就是提高Vue对DOM的渲染能力。一般会指定一个变量一个唯一的数值作为key,比如数据库查出来数据的主键值。那么key的作用到底是啥呢?前面说到改变数据后,Vue会对比两次的变化情况,以最小的代价对原DOM进行修改,那么在通过v-for输出数据后,对列表数据元素有插入或者删除,Vue并不知道插了那个元素还是删了哪个元素,只能从头开始一一对应的进行比对,被插入或删除的元素后所有的元素都会被重新渲染(错开了一个元素),所以比较好的解决办法就是列表的每个元素设置一个唯一的key值,Vue只要追踪这些key(key值相同的就不用再重新渲染),Vue就知道列表元素哪些被删掉,哪些被插入,从而以最小的代价修改DOM。当然,如果key值重复了,Vue就会报一个warn:?Duplicate keys detected: 'XXX'. This may cause an update error.意思就是说key值重复了,可能会有错。简言之,如果对效率没啥要求,key设不设置都是一样的。在大型项目中,建议加入key值,特别是用Vue脚手架来开发程序。同时提醒key前面要加冒号,将赋值当做变量。

v-for还可以循环数字 v-for="item in 10" item会自动从1循环到10.

当v-for和v-if在一个标签中时,v-for的优先级比v-if要高,解决的办法就是用template标签嵌套div标签,外层template标签用v-for循环,内层div标签用v-if显示即可。

说到数据绑定,必须要说的一个指令就是:v-model指令,即双向数据绑定指令。啥叫双向数据绑定?即DOM改变了,影响数据,数据改变了又会影响DOM,这就是双向的意思。比如:<input type="text" v-model="mytext">{{ mytext }},换句话说数据驱动就是通过改变数据来改变DOM,这个一般是后端数据返回之后,会通过前端通过数据驱动将数据渲染到页面上。而用户对页面的一些操作,比如CheckBox勾选,比如input输入款输入数据,这些操作的结果返回至数据上就是数据的双向绑定。

既然是用户的输入会影响数据,那么不同的组件输入组件的如何呢?接下来就说说,说到与用户交互,第一点就是input框,这个很简单,背后就是一个字符串,这个没啥可说的。包括textarea背后也是一个字符串,接下来就是单/多选框,CheckBox:

?只有一个checkbox的话,一般是传true或者false

<input type="checkbox" v-model="checkbox_value"/>a

?上述,如果选中的话,checkbox_value的值就是true,没有选中的话就是false。如果不想使用true或者false,就可以在属性值上绑定true-value和false-value。

<input type="checkbox" v-model="checkbox_value" true-value="a" false-value="not_a"/>a

如果多选框有多个选项,如下:?

<input type="checkbox" v-model="checkbox_value" value="a"/>a <input type="checkbox" v-model="checkbox_value" value="b"/>b <input type="checkbox" v-model="checkbox_value" value="c"/>c <input type="checkbox" v-model="checkbox_value" value="d"/>d

CheckBox的标签有两个要素,一个是v-model还有一个就是value值。value值代表的是这个选项的值,v-model后面绑定的值代表的是这一个多选框组所的选中的值。v-model绑定同一个值,就代表是同一个多选框组。上图中最终的选值会形成一个数组赋值给checkbox_value。当然

如果是radio,即单选框,那么最终形成的绑定值不是一个数组,而是一个值。

<input type="radio" v-model="radio_value" value="a"/>a <input type="radio" v-model="radio_value" value="b"/>b <input type="radio" v-model="radio_value" value="c"/>c <input type="radio" v-model="radio_value" value="d"/>d

选中哪个,就会把哪个value的值赋值给radio_value.?

接下来,我们看看select如何进行数据双向绑定。

<select v-model="message"> <option>A</option> <option>B</option> <option>C</option> </select>

?对于下拉选择框的绑定,则是通过字符串来进行绑定,选择哪个就会将哪个选项的标签内文字赋值给message,比如选择A,那么message的值就是A。如果给每个option标签增加一个value,那么与message进行双向数据绑定的值就是value的值。

多选的级联选择框,则message绑定出的就是一个数组,这一点与多选框与单选框是有相似的地方的。

option的value属性可以传一个对象,如下:

<select v-model="message"> <option value={ value: 'A' }>A</option> <option value={ value: 'B' }>B</option> <option value={ value: 'C' }>C</option> </select>

此时,message中传的就是{ value: 'A' }这样的一个对象。?

插值表达式中可以放函数表达式,比如:{{ Func() }}。函数表达式的结果就是函数的返回值,在写的时候一定要加。

v-model有修饰符可以修饰一下,比如<input type='text' v-model.lazy="data" /> 就是给input框上加了一个懒加载的修饰符,这样的话,输入框就不会一有改变就会触发双向绑定,而是会在失去焦点时才会触发。这样的修饰符对于v-model来说还有两个,第一个是number:<input type='text' v-model.number="data" />就是可以将输入的数据转化为数字,当然,能转化的才会转化,不能转化的会变为空。第二个就是:<input type='text' v-model.trim="data" />,作用是去掉绑定字符串的首尾空格。

?

1.2.在class控制方面得到体现的。

如果我们有一个需求就是如果可以随机的根据需求来组合一些class,那么在传统的jQuery上,我们需要在业务上处理完数据之后,还要根据业务的数据需求来通过jQuery来操作DOM节点的class,也就是说动态调整class,如果这个需求在Vue里怎么通过数据驱动方式得到体现呢?

最基本的就是通过变量进行绑定:

<div id="app"> <div :class="classString"> 我是内容 </div> </div> <script> new Vue({ el: '#app', data(){ return { classString: 'red' } } }) </script> <style> .red { color: red; } </style>

第一种方法是对象方法,具体如下:

<div id="app"> <div :class="classString"> 我是内容 </div> </div> <script> new Vue({ el: '#app', data(){ return { classObj: { red: true, green: true } } } }) </script> <style> .red { color: red; } .green { color: green } </style>

还有一种方法就是数组写法。

<div id="app"> <div :class="classArray"> 我是内容 </div> </div> <script> new Vue({ el: '#app', data(){ return { classArray: [ 'red' , 'green'] } } }) </script> <style> .red { color: red; } .green { color: green } </style>

也可以将数组和对象混合进行写:

<div id="app"> <div :class="classArray"> 我是内容 </div> </div> <script> new Vue({ el: '#app', data(){ return { classArray: [ 'red' , 'green', {brown: true}] } } }) </script> <style> .red { color: red; } .green { color: green } .brown { color: brown } </style>

class 在父子组件传值上也有一定的应用,如下代码:

<div id="app"> </div> <script> const app = Vue.createApp({ data(){ return { classArray: [ 'red' , 'green', {brown: true}] } }, template: ` <div :class="classArray"> 我是内容 <demo class="green" /> </div> ` }) app.component('demo', { template: `<div :class="$attrs.class">one</div>` } app.$mount("#app") </script> <style> .red { color: red; } .green { color: green } .brown { color: brown } </style>

子组件中,通过$attrs可以通过父组件向子组件传递class的值?

1.3.在style控制方面得到体现。

与class控制相似,动态调整style也有对象方法和数组方法。首先看一下对象方法

<div id="app"> </div> <script> const app = Vue.createApp({ data(){ return { classArray: [ 'red' , 'green', {brown: true}], styleString: 'color: yellow', styleObj: { color: 'orange' }, } }, template: ` <div :style="styleString"> 我是内容 </div> <div :style="styleObj"> 我是内容2 </div> ` }) app.$mount("#app") </script> <style> .red { color: red; } .green { color: green } .brown { color: brown } </style>

从上可以看出通过数据绑定来扩展style的写法,也有字符串写法和对象写法两种。?

1.4.特殊的地方

Vue是不能检测到通过索引值来改变数组的事件的。前面说到,Vue是通过重写了一些js的方法,在方法中重写了get、set函数拦截到值,再进行DOM更新的。而通过索引值改变数组,Vue无法通过get、set方法拦截到索引值,所以就无法通过数据响应来更新DOM值了。通过使用数组变更函数进行数组操作是可以响应DOM的,有push pop shift unshift reverse concat等函数。

在Vue3开始,就可以通过索引值操作数组,或者直接操作对象元素也会引起DOM的变化。

2.模糊查询之 filter

首先filter不会改变原数组。

filter()参数接受一个函数。函数返回false就是不通过,返回true就是通过。看如下代码:

arr=[1,2,3,4,5,6,7,8,9] var arr2 = arr.filter(item=>{ return item>3 这个就是将数组中元素值大于3的返回,item就是每次从数组中取的值 }) 换句话说就是挨个儿遍历数组,满足return后面条件的,就会返回。 3.关于事件处理器? 事件触发器的三种写法: {{ count }} <button @click="handlerFunc()">点击我</button> <button @click="handlerFunc2">点击我</button> 事件中不加小括号,会自动将事件对象传过来。 想要传参数只能加小括号。 如果又想拿到事件对象,又想传参,写法如下: <button @click="handlerFunc3($event,a)">点击我</button> a就是自己的参数,$event就是事件对象。$event是固定写法。 <button @click="count++">点击我</button> 简单的代码可以写在HTML中 <script> el:#app data:{ count:0 } methods:{ handlerFunc(){ this.count++ } handlerFunc2(){ this.count++ } } </script>

事件会进行冒泡,即出发里面的时间,会从内向外将所有事件都触发一遍。那么如何阻止冒泡呢??

首先可以通过sopPropagation方法来阻止冒泡。即将事件对象拿到后,调用该函数。如事件对象通过$event传到形参evt中,直接evt.stopPropagation()就行了。

当然,也可以通过事件修饰符来进行阻止冒泡,阻止父标签的事件触发。<div @click.stop="handlerFunc">阻止冒泡</div>。这个方法是从孩子角度阻止事件冒泡到父标签。我们也可以通过父标签来阻止子标签的事件:<div @click.self="handlerFunc">...</div>,加上self的事件修饰符,标签只相应自己的事件,对于子标签冒泡上来的事件则会忽略。

阻止标签的默认行为,比如阻止a标签的href功能,同样也可以通过事件修饰符来完成。即:<a href="·" @click:prevent> 阻止默认行为</a>。当然也可以尝试用原始的preventDefault来完成。

还有一种事件修饰符是让事件只触发一次:<div @click.once="handlerFunc">...</div>。当然,我们也可以自己手动解绑事件:<div @click="isActive && handlerFunc()">手动事件解绑</div>。在handlerFunc函数中,将isActive赋值为false,就不会再触发handlerFunc函数了。

之前说的都是鼠标事件响应,那么按键的事件如何触发呢?

<input type="text" @keydown="handleKeyDown">按键触发</input>对于keydown传回的事件对象中会包含按键的值,即通过ev.keyCode拿到键值,ev为传回的时间对象。以上是通过事件对象传回来自己拿到键值判断的,那么如何像其他事件一样通过时间修饰符实现呢?比如:<input type="text" @keydown.enter="handleKeyDown">就是通过.enter的事件修饰符实现了只按下回车键的时候,才会触发handleKeyDown事件。同样的事件修饰符还有:.up .down .left .right :方向符号、.space:空格键。最厉害的还是可以直接点键值就行了,比如:@keydown.13="handleKeyDown"就会触发键值为13的按键按下事件。

?v-on绑定事件事件修饰符有.stop .prevent .capture .self .once .passive用法为:@click.prevent="handleClick".

.stop 调用?event.stopPropagation(),阻止事件冒泡。.prevent???调用?event.preventDefault().capture?添加事件侦听器时使用 capture 模式。.self?只当事件是从侦听器绑定的元素本身触发时才触发回调。 点击按钮,则不会触发handleDivClick事件,只有在点击只有div的部分才会触发handleDivClick事件 <div @click.self="handleDivClick"> {{ counter }} <button @click="handleClick">button</button> </div>

.once 事件只触发一次.passive 提升页面滚动的性能

对应鼠标的事件修饰符有,使用方法为@click.left:

.left.right.middle

对应的键盘修饰符有,比如@keydown.enter:

.enter.tab.delete?(捕获“删除”和“退格”键).esc.space.up.down.left.right.ctrl.alt.shift.meta

提示

注意:在 Mac 系统键盘上,meta 对应 command 键 (?)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (?)。在 Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。在其他特定键盘上,尤其在 MIT 和 Lisp 机器的键盘、以及其后继产品,比如 Knight 键盘、space-cadet 键盘,meta 被标记为“META”。在 Symbolics 键盘上,meta 被标记为“META”或者“Meta”。?

上述的键盘修饰符指的都是别名,最全的还是通过之前所讲的,利用keyCode来实现键盘的监听。?

此外还有精确修饰符.exact

@click.ctrl.exact 只有按住ctrl再点击才会触发事件,多按其他按键没有用。?

事件修饰符还可以串联,比如:

<a @click.stop.prevent="doThat"></a>

?还有就是之前在v-bind中所述的动态绑定在绑定事件的时候也会有所体现,如下:。

data() { return { event:'click', message: 'HelloWorld!' } }, template: `<div @[event]="handleClick" > {{ message }} </div>`

通过上述绑定,则[event]就指代了event所代表的值。?

处理事件的方法第一个参数默认回调的是这个时间的本身,如:

<button @click="handleClick">点击</button> methods: { handleClick(event){ 此处的event默认指时间本身 } }

那么如果本身就要额外传递参数,同时又想获得事件对象,该怎么处理呢?

<button @click="handleClick(2, $event)">点击</button> methods: { handleClick(count,event){ 此处的event默认指时间本身 } }

如上,只要传一个$event参数就可以了。

如果绑定一个时间要执行多个函数,则采用:

<button @click="handleClick(), handleClick2()">点击</button> 4. 计算属性

定义起来像个方法,用起来像个属性。

<div id="app"> {{ get_sum }} </div> <script> new Vue({ el:#app, computed:{ get_sum(){ return 12 } } }) </script> <style> . </style>

用的时候不要加括号,如果加括号的话就是方法。

那为啥不直接用方法呢?

因为计算属性比方法的效率高。如果计算数不变(计算属性内的函数所涉及到的成员变量不变)的话,那么多次调用计算属性,计算属性只会计算一遍。而方法则是调用一次执行一次,效率不如计算属性那么高。换句话说,就是计算属性是带有缓存的,缓存的数据不变,是不会渲染页面的。

5. 监听器watch的使用

watch可以用来监听某一个值或者状态发生变化,会触发一个函数。

<div id="app"> {{ get_sum }} </div> <script> new Vue({ el:#app, data(){ return{ total:[] } } watch:{ total(newValue,oldValue){ 这个watch用来监听data中的total变化情况。 如果发生变化就会触发这个函数,并将新值和旧值分别传给newValue和oldValue } } }) </script> <style> . </style>

默认情况下,watch在初始化之后是不执行的。如果想watch在页面初始化的时候,就执行,则需要换种写法,如下:

<div id="app"> {{ get_sum }} </div> <script> new Vue({ el:#app, data(){ return{ total:[] } } watch:{ total: { immediate: true,// 此处设置为true就代表立即执行 deep: true, // 如果监控的数据是对象、数组相互嵌套的,就需要进行设置这个选项 handler(newValue,oldValue){ 这个watch用来监听data中的total变化情况。 如果发生变化就会触发这个函数,并将新值和旧值分别传给newValue和oldValue } } } }) </script> <style> . </style>

如果能用computed实现就用computed实现。但是computed与watch之前使用的还是有一些规律可循:

computed适合那些一个值受多个值控制,如果多个值中有一个值变化,那么就是用computed监控受影响的值。

watch适合一个值变化来影响其他值的情况。

computed有缓存属性。而监听器选项提供出了更通用的方法,适合执行异步操作或较大开销操作的情况。

6. 其他的注意点 methods中的方法不要使用箭头函数,methods中的this指向Vue实例,但是如果使用箭头函数则


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #Vue #数据驱动 #ampltmeta