Vue(三)v-指令

392 阅读4分钟

尽管 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

参考阅读