Vue知识点唠嗑之数据驱动

2024-02-05 17:40

本文主要是介绍Vue知识点唠嗑之数据驱动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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:#appdata:{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="www.baidu.com" @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实例,但是如果使用箭头函数则

这篇关于Vue知识点唠嗑之数据驱动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/681678

相关文章

Python将博客内容html导出为Markdown格式

《Python将博客内容html导出为Markdown格式》Python将博客内容html导出为Markdown格式,通过博客url地址抓取文章,分析并提取出文章标题和内容,将内容构建成html,再转... 目录一、为什么要搞?二、准备如何搞?三、说搞咱就搞!抓取文章提取内容构建html转存markdown

Python获取中国节假日数据记录入JSON文件

《Python获取中国节假日数据记录入JSON文件》项目系统内置的日历应用为了提升用户体验,特别设置了在调休日期显示“休”的UI图标功能,那么问题是这些调休数据从哪里来呢?我尝试一种更为智能的方法:P... 目录节假日数据获取存入jsON文件节假日数据读取封装完整代码项目系统内置的日历应用为了提升用户体验,

在React中引入Tailwind CSS的完整指南

《在React中引入TailwindCSS的完整指南》在现代前端开发中,使用UI库可以显著提高开发效率,TailwindCSS是一个功能类优先的CSS框架,本文将详细介绍如何在Reac... 目录前言一、Tailwind css 简介二、创建 React 项目使用 Create React App 创建项目

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

Redis 中的热点键和数据倾斜示例详解

《Redis中的热点键和数据倾斜示例详解》热点键是指在Redis中被频繁访问的特定键,这些键由于其高访问频率,可能导致Redis服务器的性能问题,尤其是在高并发场景下,本文给大家介绍Redis中的热... 目录Redis 中的热点键和数据倾斜热点键(Hot Key)定义特点应对策略示例数据倾斜(Data S

Vue中组件之间传值的六种方式(完整版)

《Vue中组件之间传值的六种方式(完整版)》组件是vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用,针对不同的使用场景,如何选择行之有效的通信方式... 目录前言方法一、props/$emit1.父组件向子组件传值2.子组件向父组件传值(通过事件形式)方