尽管 Vue.js 的官方文档已经写的足够清楚易懂,但是重点还是要通过整理才能消化成自己的。这篇博客记录了我在阅读文档后的感悟与总结。
v-text 与 v-html 模版插值
- v-text 相当于 innerText,会把字符串作为文本内容插⼊页面。
- v-html 相当于 innerHTML,会把字符串作为HTML片段插⼊页⾯,容易引起XSS攻击,谨慎使用。
<template>
<div>
<span v-text="text"></span>
<span v-html="text"></span>
</div>
</template>
<script>
export default {
data() {
return {
text: '<style>body{ background:red; }</style>'
}
}
}
</script>
v-if 与 v-show 条件渲染
-
v-if切换会创建/销毁DOM元素,切换开销更高,v-show切换只是对元素展示/隐藏(display: none) -
v-if惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。v-show不管初始条件是什么,元素总是会被渲染。
v-for 列表循环
key 的作用:实现数据的追踪,如果实现了数据的删除/顺序的调整,仍然可以追踪到,没有key容易引发混乱。
v-on 与 @click 绑定事件
- 有两种方法去绑定事件,一种是用
v-on:click,另一种是用@click。 - 用
@click后面接的事件名,是 methods 里面的方法,方法里传递的参数既可以是固定值,也可以使用 data 里面的属性
<!-- 方法一 -->
<span v-on:click="sayHello">点我</span>
<!-- 方法二 -->
<span @click="sayHello">点我</span>
<!-- 带参数:普通参数 -->
<span @click="sayHello('hhh')">点我</span>
<!-- 带参数:data里属性name做参数 -->
<span @click="sayHello(name)">点我</span>
<!-- 同时触发两个事件 -->
<span @click="sayHello('hhh'),sayHi('hahaha')">点我</span>
@click="handler"和@click="handler()"区别:打印参数第一个是事件,第二个是undefined
v-bind 为元素绑定属性
给元素绑定了属性name,值为data里的属性名username对应的属性值
<son v-bind:name="username" />
可以简写成
<son :name="username" />
注意:
<son :name="username" /> <!--传的是表达式 -->
<son name="username" /> <!--传递的是字符串 "username" -->
v-model 组件内实现表单双向绑定
基础用法:作用在表单元素上
在<input>、<textarea>及 <select> 元素上完成数据的双向绑定。
<input v-model="message" /> {{ message }}
<script>
data() {
return {
message: ''
}
}
</script>
v-model 本质:语法糖
我们习惯的写法:
<input v-model="message">
实际上的完整写法:
<input :value="message" @input="message=$event.target.value" />
或者
<input :value="message" v-on:input="message=$event.target.value" />
input 元素本身有个input 事件,每当输入框内容发生变化,就会触发 input 事件,把最新的value值传给传递给 message ,完成双向数据绑定。
- $event 指代当前触发的事件对象;
- $event.target 指代当前触发的事件对象的dom;
- $event.target.value 就是当前dom的value值;
- 在
@input方法中,value => sth - 在
:value中,sth => value
特殊用法
v-model 还可用于父子组件之间数据的双向绑定。这里需要用到父子传值的相关知识:
1.父组件把num传递给son组件
<template>
<div>
{{ num }}
<son v-model="num" />
<!-- 等价于 -->
<son v-bind:value="num" v-on:input="num=$event.target.value" />
</div>
</template>
<script>
import son from '@/src/son.vue' // 引入子组件
export default {
components: {
son // 注册子组件
},
data() {
return {
num: 100
}
}
</script>
2.子组件内的 props里的numberValue,接收父组件的传值num并使用
son.vue
<template>
<div>
{{ numberValue }}
</div>
</template>
<script>
export default {
props: {
numberValue: {
type: Number,
required: true
}
}
</script>
注意:以上这种情况,子组件中直接修改 numberValue 会进行报错,需要再将其传入父组件才可以进行修改。这就需要在父组件的子组件标签上定义一个自定义的事件,通过在子组件中使用$emit('update:属性名',值)的方法将值传入父组件
son.vue
<template>
<div>
{{ numberValue }}
<button @click=$emit('update: numberValue',numberValue+1)点我</button>
</div>
</template>
子组件想要修改数据需要去触发事件,父组件需要去响应事件,数据才会改变。
单向数据流
- 单向数据流:父组件能直接传递数据给所有的子组件,但是子组件不能随意修改父组件的数据。
- 双向数据流:父组件能直接传递数据给所有的子组件,子组件也可以修改父组件的数据状态。 为什么要使用单向数据流? 让数据的传递变得简单,可追溯。如果使用双向数据流,任何一个子组件都可以直接修改父组件的数据,其他子组件的数据也会被修改,最终我们拿到结果数据单,却不知道是哪个子组件修改了数据,数据的追溯变得复杂。
v-model 实现双向数据流
- 父组件 —> 子组件:设置子组件的props,直接传递数据给子组件。
- 子组件 —> 父组件:子组件内部 emit ⼀个自定义事件,父组件可在子组件上绑定该事件的监听,来处理子组件 emit 的事件和数据。
注意:这种双向绑定是可控的,不是默认自动的双向绑定。
v-model 语法糖
//父组件
<son v-bind:user="username" @update:user="username=$event" />
上述写法等价于
<son v-model:user="username" />
注意:v-model:user="username"和:user="username"的区别:
:user="username":给子组件传递一个 props属性,值是当前父组件的data属性username的属性值。v-model:user="username":父->子传参之外,父还监听@update:user事件,子组件也会更新这个user属性来更新父组件的username值。
.sync修饰符
假设有以下场景,爸爸给儿子钱, 儿子要花钱,爸爸和儿子通过属性 money 来沟通
儿子:Child.vue
<script>
export default {
props: ["money"] //接受外部数据money
};
</script>
爸爸:App.vue
<template>
<div class="app">
<Child :money="total" /> <!--向子组件的money属性传入参数 变量total -->
</div>
</template>
<script>
import Child from "./Child.vue"; // 引入儿子组件
export default {
data() {
return { total: 10000 };
},
components: { Child: Child } //定义的引入组件的名字
};
</script>
第一步
儿子触发一个要花钱的事件,然后告诉爸爸花完之后剩多少,这里假设儿子每次花100元。儿子用 $emit触发update:money事件,并且告诉爸爸,钱花了还剩下money-100
在child.vue里
<button @click="$emit('update:money', money - 100)">
<span>花钱</span>
</button>
原因:子组件不能直接修改外部传入的props的值,只能由父组件修改,因此只能用触发事件操作
第二步
爸爸用v-on:update:money监听 update:money事件,并用 $event获取到$emit参数:
App.vue里
<Child :money="total" v-on:update:money="total = $event"/>
由于以上两步操作非常麻烦,于是就有了 .sync语法糖
.sync用法
是直接在child :money 后加一个.sync修饰符,在App.vue里:
<Child :money.sync="total" />
等价于之前的:
<Child :money="total" v-on:update:money="total = $event" />
在这里使用.sync 完成的功能是:
- 绑定money属性
- 监听update:money事件
- 更新money属性
总结
.sync功能:当一个子组件改变了一个 prop的值时,这个变化也会同步到父组件中所绑定,会被扩展为一个自动更新父组件属性的 v-on 监听器。
.sync与v-model区别是
- 相同点:都是语法糖,都可以实现父子组件中的数据的双向通信。
- 区别点:格式不同: v-model=“num”, :num.sync=“num”
v-model: @input + value
:num.sync: @update:num