首页 > 其他分享 >Vue3 基础 – 快速上手 & 常用指令

Vue3 基础 – 快速上手 & 常用指令

时间:2023-09-25 17:04:44浏览次数:63  
标签:常用 createApp app 绑定 指令 Vue3 const data


1. 在 HTML 网页中使用 vue3 的3个基本步骤

a.通过 script 标签的 src 属性,在当前网页中全局引入 vue3 的脚本文件:

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

b.创建 vue3 的单页面应用程序实例:

// 2.1 从 Vue 对象中解构出 createApp 函数
const { createApp } = Vue

// 2.2 调用 createApp 这个函数,就能够创建出一个单页面应用程序的实例
const app = createApp()

// 2.3 调用 app 实例对象上的 mount() 函数,
// 指定单页面应用程序 app,实际要控制页面上哪个区域的渲染
app.mount('#app')

c.声明 vue3 的单页面应用程序实例,实际要控制的页面区域:

<!-- 注意:如果内容为空,则 vue3 会在提示一个警告消息:
[Vue warn]: Component is missing template or render function. at <App> -->
<div id="app"></div>

2. 定义和渲染数据

a.在调用 createApp() 函数时,可以提供一个对象作为配置参数,例如:

const app = createApp({ /*配置对象*/ })

b.如果想提供要渲染的数据,可以在步骤1的配置对象中,通过 data 节点提供渲染期间要使用的数据:

const app = createApp({
 // 2.1 注意:data 节点是一个函数
 data() {
   // 2.2 在 data 函数内部,return 的这个对象,就是数据对象,
   // 要渲染的数据,可以直接写到这个对象中,例如 return { name: 'ls' }
   return {}
 }
})

c.在步骤2的 data 节点中,定义一个名为 name 的数据,值是 zhangsan:

const app = createApp({
 data() {
   return {
     name: 'zhangsan'
   }
 }
})

d.在 vue3 控制的模板结构中,使用 {{ 数据名 }} 语法,把数据渲染出来:

<div id="app">
<h1>我是:{{ name }}</h1>
</div>

e.拓展:当我们修改 data 节点下的数据后,即可看到页面上的 HTML 内容会自动被刷新。这就是 vue 的强大之处:数据驱动视图。修改 data 数据的示例代码如下:

app._instance.proxy.name = 'wangwu'

3. vue3 中常用的渲染指令

在 vue 中,指令是带有 v- 前缀的特殊 attribute,它是 vue 提供的特殊语法,大家有必要掌握 vue 中常用指令的使用。

指令能够辅助前端程序员高效地把数据渲染为 HTML 的结构,而程序员不需要调用任何操作 DOM 的 API。

3.1常用指令的分类

1.内容渲染指令

a. 插值表达式

插值表达式(又叫做:Mustache)的语法为 {{ }},vue 在解析模板期间,会把 {{ }} 所在的位置,替换为对应的数据值,例如:

<h1>大家好,我是:{{ name }}</h1>

 vue 会把 name 的值,替换到 {{ name }} 所在的位置。

注意:插值表达式 {{ }} 是唯一一个不以 v- 前缀开头的指令。

b.v-text

v-text 指令用来填充 HTML 元素的内容,如果 HTML 元素内部有其它内容存在,则会被覆盖掉。语法格式如下:

<h3 v-text="msg">展示看看</h3>

对应的数据为:

const app = createApp({
  data() {
    return {
      msg: '我是绑定的数据'
    }
  }
})

 注意:由于 v-text 指令存在覆盖已有内容的问题,所以在实际开发中它很少被用到。最常用的还是 {{ }} 插值表达式,因为它只是占位符,不会覆盖已有内容。

c.v-html

v-html 指令用来渲染带有 HTML 标记的文本内容,它可以把 HTML 标记解析为真正的 HTML 元素,并插入到模板中渲染。

而插值表达式和 v-text 指令只会把 HTML 标记渲染为纯文本,而不是 HTML。

v-html 的语法格式如下:

<div v-html="rawHtml"></div>

 对应的数据为:

const app = createApp({
  data() {
    return {
      rawHtml: '<span style="color: red;">少年强中国说</span>'
    }
  }
})

2. 属性绑定指令 

a.v-bind

v-bind 指令用来为元素的属性绑定动态的属性值。指令语法如下:

<div v-bind:title="titleMsg">xxx</div>

对应的数据为: 

const app = createApp({
  data() {
    return {
      titleMsg: '哇哈哈'
    }
  }
})

又例如,为图片的 src 属性动态绑定属性的值: 

<img v-bind:src="url" />

对应的数据为: 

const app = createApp({
  data() {
    return {
      url: 'https://img.yzcdn.cn/vant/cat.jpeg'
    }
  }
})

 b.v-bind的简写

在实际开发中,v-bind 指令的使用频率非常高,为了简化它的写法,vue 规定 v-bind 指令可以简写为英文的 : 且二者是完全等价的。如上面的例子可以使用 : 简写为:

<div :title="titleMsg">xxx</div>
<img :src="url"

对应的数据为: 

const app = createApp({
  data() {
    return {
      titleMsg: '哇哈哈',
      url: 'https://img.yzcdn.cn/vant/cat.jpeg'
    }
  }
})

 注意:今后在 vue 项目开发中,只要看到某个属性前面出现了英文的 : 那么,一定是为这个属性绑定了动态的值。

c.绑定布尔值

在 vue 中,某些属性的取值可以是布尔值 true 或 false,表示当前的属性是否应该应用于当前的元素。例如 disabled 属性:

<!-- 禁用按钮A -->
<button :disabled="true">按钮A</button>

<!-- 不禁用按钮B -->
<button :disabled="false">按钮B</button>

与之类似的,还有 radio 和 checkbox 的 checked 属性: 

<!-- 默认选中“男” -->
<input type="radio" name="gender" :checked="true">男
<input type="radio" name="gender">女

<!-- 默认选中“足球”和“乒乓球” -->
<input type="checkbox" name="hobby">篮球
<input type="checkbox" name="hobby" :checked="true">足球
<input type="checkbox" name="hobby" :checked="true">乒乓球

另外,表单元素 select 下的 option 选项的 selected 属性,也可以绑定布尔值: 

<select>
  <option value="北京">北京</option>
  <option value="上海" :selected="true">上海</option>
  <option value="广州">广州</option>
</select>

d.动态绑定多个值

 如果要为某个元素同时绑定多个动态的属性值,可以把多个动态属性封装为一个 JavaScript 对象

const app = createApp({
  data() {
    return {
      // propObj 对象中封装了一系列属性的键值对
      attrsObj: {
        id: 'box',
        class: 'container',
        title: '布局容器'
      }
    }
  }
})

通过不带参数的 v-bind 指令,即可方便的把 attrsObj 对象中封装的属性,一次性绑定到对应的元素上:

<div v-bind="attrsObj">顶部 header 区域</div>

 注意:不带参数的 v-bind 指令,指的是省略了 :属性名 的用法。

e. 拓展:使用 JavaScript 表达式

在 vue 的数据绑定中,除了支持简单的属性名绑定之外,还支持完整的 JavaScript 表达式绑定

例如,以下这些都属于简单的属性名绑定,它们是直接把 data 中数据项的名字,绑定到了模板中:

<div>我是:{{ name }}</div>

<div v-text="msg"></div>

<img :src="url" />

 除此之外,还支持表达式的绑定,例如:

<!-- 函数的调用 & 数学运算 -->
<div>我是:{{ name.toUpperCase() }},我今年{{ age + 1 }}岁了。</div>

<!-- 函数的调用 -->
<div v-text="msg.split('').reverse().join('')"></div>

<!-- 字符串的拼接 -->
<img :src="'https://img.yzcdn.cn/vant/' + url" />

<!-- 三元表达式 -->
<div>{{ age >= 18 ? '抽烟喝酒烫头' : '可乐牛奶娃哈哈' }}</div>

 对应的数据如下:

const app = createApp({
 data() {
   return {
     name: 'liulongbin',
     age: 17,
     msg: '冯绍峰',
     url: 'cat.jpeg'
   }
 }
})

3.双向绑定指令

v-model 双向绑定指令,简化了表单元素赋值和取值操作。

v-model 的作用:

1.data 数据源发生变化,自动重新渲染页面

2.表单数据发生变化,自动更新到 data 数据源中

a.文本框的双向绑定

input 元素通过 v-model 指令,可以方便地进行赋值和取值,示例代码如下:

<p>Message 的值是:{{ message }}</p>
<input type="text" v-model="message">

对应的数据如下:

const app = createApp({
  data() {
    return {
      message: 'hello'
    }
  }
})

b.多行文本框的双向绑定

textarea 元素通过 v-model 指令,可以方便地进行赋值和取值,示例代码如下:

<p>Message 的值是:</p>
<pre>{{ message }}</pre>
<textarea v-model="message"></textarea>

 对应的数据如下:

const app = createApp({
  data() {
    return {
      // 注意:这里的 \n 是换行符
      message: 'hello \nworld.'
    }
  }
})

c.复选框的双向绑定

单一复选框的双向绑定,绑定的是布尔类型的值:

<p>复选框选中的flag值为:{{flag}}</p>
<input type="checkbox" v-model="flag">

const app = createApp({
 data() {
   return {
     // 是否被选中
     flag: false
   }
 }
})

多个复选框的双向绑定,绑定的是数组类型的值,而且每个 checkbox 必须通过 value 属性提供选中项的值

<p>多个复选框选中的 hobbies 值为:{{ hobbies }}</p>
<label><input type="checkbox" v-model="hobbies" value="篮球">篮球</label>
<label><input type="checkbox" v-model="hobbies" value="足球">足球</label>
<label><input type="checkbox" v-model="hobbies" value="冰球">冰球</label>

const app = createApp({
 data() {
   return {
     // 选中的值
     hobbies: []
   }
 }
})

d.单选按钮的双向绑定

单选按钮的特点是多选一,所以对单选按钮进行双向绑定时,需要把多个单选按钮通过 v-model 指令绑定到同一个数据源,并通过 value 属性指定选中后的值:

<p>单选按钮选中的 gender 值为:{{ gender }}</p>
<label><input type="radio" v-model="gender" value="男">男</label>
<label><input type="radio" v-model="gender" value="女">女</label>

数据如下:

const app = createApp({
  data() {
    return {
      // 选中的值
      gender: '男'
    }
  }
})

e.选择器的双向绑定

单选选择器的双向绑定,只允许选中一个值:

<p>选中的城市为:{{ city }}</p>
<select v-model="city">
 <option value="">请选择</option>
 <option value="beijing">北京</option>
 <option value="shanghai">上海</option>
 <option value="nanjing">南京</option>
</select>


const app = createApp({
 data() {
   return {
     city: ''
   }
 }
})

多选选择器的双向绑定,允许选中多个值,所以需要绑定数组格式的数据源:

<p>选中的城市为:{{ areas }}</p>
<select v-model="areas" multiple>
 <option value="shunyi">顺义区</option>
 <option value="haidian">海淀区</option>
 <option value="daxing">大兴区</option>
</select>


const app = createApp({
 data() {
   return {
     areas: []
   }
 }
})

f.v-model 的 .lazy 修饰符

默认情况下,v-model 会在每次 input 事件后更新数据。可以添加 .lazy 修饰符来改为在每次 change 事件后更新数据:

<input v-model.lazy="msg" />

g. v-model 的 .number 修饰符

如果你想让用户输入自动转换为数字,你可以在 v-model 后添加 .number 修饰符来管理输入:

<input v-model.number="age" />

注意:

  1. 如果该值无法被 parseFloat() 处理,那么将返回原始值。
  2. number 修饰符会在输入框有 type="number" 时自动启用。

h.v-model 的 .trim 修饰符

如果你想要默认自动去除用户输入内容中两端的空格,你可以在 v-model 后添加 .trim 修饰符:

<input v-model.trim="msg" />

4.条件渲染指令

条件渲染指令用来条件性地渲染页面上的某一部分内容。只有表达式的条件成立,才会真正渲染这一部分的内容。

常用的条件渲染指令是 v-ifv-else 和 v-else-if。其中,v-if 指令可以单独使用,也可以结合 v-else 和 v-else-if 指令实现两个多个条件的按需渲染。

1.v-if的使用

v-if 的语法格式如下:

<div v-if="表达式"></div>

其中,只有表达式的返回值为 true 时,才会真正渲染被 v-if 指令控制的 div 元素。

如果 v-if 的表达式返回值为 false,则被 v-if 指令控制的 div 不会被渲染到浏览器中。

例如:

<div v-if="flag">无敌是多么的寂寞</div>


const app = createApp({
  data() {
    return {
      flag: true
    }
  }
})

2. v-if 结合 v-else 的使用

v-if 指令可以结合 v-else 指令一起使用。

条件为真时渲染被 v-if 指令控制的元素,当条件为假时渲染被 v-else 指令控制的元素。例如:

<div v-if="age >= 18">抽烟喝酒烫头</div>
<div v-else>牛奶可乐娃哈哈</div>

注意:v-else 指令不需要通过 = 指定相应的表达式,因为 v-else 是兜底的条件,只要前面的所有条件都不满足,那么必然会触发 v-else 的执行。

3.v-if 结合 v-else-if 和 v-else 的使用

v-if 指令可以结合 v-else-if 和 v-else 指令一起使用,从而组成复杂的条件渲染逻辑。

当 v-if 或某个 v-else-if 相应的条件为真时,被控制的元素才会被渲染。

最后的 v-else 依然是兜底的条件,当所有的 v-if 和 v-else-if 条件都不成立时,才会触发 v-else 的执行。例如:

<div v-if="score === 'A'">优秀</div>
<div v-else-if="score === 'B'">良好</div>
<div v-else-if="score === 'C'">一般</div>
<div v-else>差</div>


const app = createApp({
  data() {
    return {
      score: 'A'
    }
  }
})

4. <template> 上的 v-if

正常情况下 v-if 指令只能控制单个元素的显示和隐藏。如果需要使用 v-if 控制一组元素的显示和隐藏,就需要在这一组元素之外包裹一个 div 作为容器,并将 v-if 指令应用于 div 容器之上,例如:

<div v-if="true">
  <h1>咏鹅</h1>
  <p>鹅鹅鹅,曲项向天歌。</p>
  <p>白毛浮绿水,红掌拨清波。</p>
</div>

这么做虽然能实现需求,但会在页面上渲染出一个多余的 div 容器。

更好的方案是使用 vue 内置的 <template> 元素作为外层包裹性质的容器,因为它不会被渲染为实际的元素,只起到包裹性质的作用。例如:

<template v-if="true">
  <h1>咏鹅</h1>
  <p>鹅鹅鹅,曲项向天歌。</p>
  <p>白毛浮绿水,红掌拨清波。</p>
</template>

5.v-show 指令的使用

另一个可以用来实现条件渲染的指令是 v-show。它的语法格式如下:

<h1 v-show="flag">Hello!</h1>

如果表达式的值为 true,则被控制的元素会被显示

如果表达式的值为 false,则被控制的元素会被隐藏

注意:v-show 指令不支持在 <template> 元素上使用,也不能和 v-else 搭配使用。

6.v-if 和 v-show 的对比

相同点:

v-if 和 v-show 指令都能控制元素的条件渲染。

1.如果表达式的值为 true,则被控制的元素会被显示

2.如果表达式的值为 false,则被控制的元素会被隐藏

不同点:

a.控制元素显示和隐藏的手段不同

  • v-if 指令会动态创建删除被控制的元素,从而达到切换元素显示和隐藏的目的;
  • v-show 指令仅切换了被控制元素上名为 display 的 CSS 属性,从而达到切换元素显示和隐藏的目的;

b.初始渲染性能不同:

  • 如果初始渲染时,表达式的值为 false,则 v-if 的性能更好。
  • 如果初始渲染时,表达式的值为 true,则二者性能相近。

c.频繁切换时的性能不同

  • 如果需要频繁切换元素的显示和隐藏,则 v-show 的性能更好。
  • 如果不需要频繁切换元素的显示和隐藏,则可以忽略二者的性能差别。

d.总结

  • v-if 有更高的切换开销
  • v-show 有更高的初始渲染开销

5.事件绑定指令

a.事件绑定的基本语法

为了响应用户对 DOM 元素的操作,vue 提供了事件绑定指令 v-on(简写为 @)。

当监听到 DOM 事件的触发时,会执行对应的 JavaScript 逻辑。它的语法格式为 v-on:事件名="handler" 或 @事件名="handler"。例如:

<!-- v-on 是事件绑定指令 -->
<button v-on:click="show">按钮</button>

<!-- @ 是 v-on 指令的简写形式 -->
<button @click="show">按钮</button>

上述代码演示了如何为 button 按钮绑定 click 点击事件。

除此之外,vue 还支持绑定其它类型的事件,这里就不再一一例举了。因为把 DOM 原生事件前面的 on 替换成 v-on: 或 @ 就变成了 vue 的事件绑定形式,例如:

1.onclick --> @click

2.oninput --> @input

3.onchange --> @change

b.方法事件处理器

方法事件处理器指的是:指定一个方法作为事件的处理器。例如下面的代码所示,指定了一个 show 方法作为 click 事件的处理器:

<button @click="show">按钮</button>

show 方法作为事件处理器,需要定义在 methods 节点下,例如:

const app = createApp({
  data() {
    return {}
  },
  methods: {
    show(event) { 
      console.log('ok')
      console.log(event.target.tagName)
    }
  }
})

在方法事件处理器的参数列表中,第一个形参 event 是事件对象

c.基于方法事件处理器实现数值自增

声明模板结构如下:

<p>count的值为:{{ count }}</p>
<button @click="add">+1</button>

在 data 中声明数据源 count,在 methods 中声明事件处理器 add,代码如下:

const app = createApp({
 data() {
   return {
     count: 0
   }
 },
 methods: {
   add() {
     app._instance.proxy.count++
   }
 }
})

注意:methods 节点下的方法中,this 指向的就是 app._instance.proxy。所以上述代码完全可以替换为 this.count++

d.内联事件处理器

内联事件处理器相当于原生 DOM 中的内联 JavaScript,例如数值自增的操作,可以简写成内联事件处理器的形式:

<p>count的值为:{{ count }}</p>
<button @click="count++">+1</button>
const app = createApp({
  data() {
    return {
      count: 0
    }
  }
})

注意:内联事件处理器通常用于简单的业务场景,如果涉及到复杂的业务逻辑,请使用方法事件处理器在内联处理器中调用方法

e. 在内联处理器中调用方法

首先,我们要能够明确的区分开方法事件处理器内联事件处理器

如果事件绑定的处理器是个纯粹的方法名,则是方法事件处理器,例如:

<button @click="show">按钮A</button>

除此之外,其它绑定事件处理器的形式,都是内联事件处理器,例如:

<!-- 绑定内联的 JavaScript -->
<button @click="count++">按钮C</button>

<!-- 绑定了一个方法的调用 -->
<button @click="show()">按钮B</button>

<!-- 绑定了方法的调用的同时,传递参数 -->
<button @click="show('Hello world.')">按钮B</button>

内联事件处理器的优点:解锁了模板向处理器方法传递参数的能力。

f.在内联事件处理器中访问事件对象

内联事件处理器的缺点:事件对象丢失了,无法在处理器方法中访问到事件对象 event。

上述问题的解决方案有两个,分别是:

  • 使用特殊的 $event 变量
  • 使用内联箭头函数接收并传递 event 对象

解决方案1:使用特殊的 $event 变量

<button @click="showMsg('hello world.', $event)">按钮</button>

对应的 showMsg 处理器为:

const app = createApp({
  methods: {
    showMsg(msg, event) {
      // 改变按钮显示的文本
      event.target.innerHTML = msg
      // 改变按钮的背景颜色
      event.target.style.backgroundColor = 'cyan'
    }
  }
})

解决方案2:使用内联箭头函数接收并传递 event 对象

<button @click="(event) => showMsg('你好,世界。', event)">按钮</button>

对应的 showMsg 处理器为:

const app = createApp({
  methods: {
    showMsg(msg, event) {
      // 改变按钮显示的文本
      event.target.innerHTML = msg
      // 改变按钮的背景颜色
      event.target.style.backgroundColor = 'cyan'
    }
  }
})

g. 事件修饰符

在原生 DOM 的事件处理函数中,如果想要阻止冒泡行为,则需要调用 event.stopPropagation();如果想要阻止默认行为,则需要调用 event.preventDefault()。为了提高用户的开发体验,vue 提供了更优雅的方式来阻止事件冒泡或默认行为,即:事件修饰符。

在 vue 中最常用的两个事件修饰符分别是:

  • .prevent
  • .stop

其中 .prevnet 用来阻止默认行为,例如:

<!-- 使用 .prevent 修饰了 a 链接的 click 事件 -->
<!-- 点击超链接后,会阻止超链接的默认跳转行为 -->
<a href="https://www.baidu.com/" @click.prevent="showMsg">超链接</a>

另外 .stop 用来阻止事件冒泡,例如:

<div @click="outerHandler">
  <!-- 点击内部的 button 按钮,click 事件不会向外冒泡 -->
  <!-- 所以外层的 outerHandler 处理器不会执行 -->
  <button @click.stop="innerHandler">按钮</button>
</div>

拓展:其它事件修饰符还有 .self、.capture、.once、.passive。具体用法请参考 vue3 官方文档 - 事件修饰符

h.按键修饰符

在监听键盘事件时,我们经常需要检查特定的按键,从而执行特定的操作。例如:

  • 用户在输入框中按下了 enter 键,则触发提交的函数
  • 用户在输入框中按下了 esc 键,则清空文本框的内容

示例代码如下:

<input type="text" v-model="msg" @keyup.enter="submit" @keyup.esc="clear">

 对应的 JS 处理逻辑为:

const app = createApp({
  data() {
    return {
      msg: '' // 文本框的数据
    }
  },
  methods: {
    // 该处理函数仅在用户按下 enter 键时触发
    submit() {
      console.log('提交的数据为:' + this.msg)
    },
    // 该处理函数仅在用户按下 esc 键时触发
    clear() {
      this.msg = ''
    }
  }
})

i.按键别名与按键名的获取

vue 为常用的按键提供了官方内置的按键别名,列表如下:

  • .enter
  • .tab
  • .delete (捕获“Delete”和“Backspace”两个按键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

如果上述列表中没有你想监听的按键,则可以使用 $event.key 先获取按键的名称,再把获取到的按键名称转为 kebab-case 形式,最后利用转换得到的按键名进行监听即可,例如下面的代码监听了 CapsLock 按键:

<p>输入状态:{{ isUpperCase ? '大写' : '小写' }}</p>
<input type="text" v-model="msg" @keyup.caps-lock="changeMode">

对应的 JS 逻辑为:

const app = createApp({
  data() {
    return {
      msg: '', // 文本框的数据
      isUpperCase: false // 是否为大写输入模式
    }
  },
  methods: {
    // 仅当用户按下的是 CapsLock 键,才触发此函数的执行
    changeMode() {
      this.isUpperCase = !this.isUpperCase
    }
  }
})

j.系统按键修饰符

如果在触发事件的时候,想要判断用户是否同时按下了 Ctrl、Alt 等系统按键。此时可以使用 vue 内置的系统按键修饰符,主要有以下4个:

  • .ctrl
  • .alt
  • .shift
  • .meta [注意:meta 在 Windows 键盘上指的是 Windows 键(⊞),在 Mac 键盘上指的是 Command 键(⌘)]

例如,下面的代码监听了触发 div 的 click 事件时,是否同时按下了特定的系统按键,从而改变 div 的形状和外观:

<!-- 点击 div 的时候, -->
<!-- 1. 如果同时按下了 Ctrl 键,则添加 square 类样式 -->
<!-- 2. 如果同时按下了 Alt 键,则添加 round 类样式 -->
<!-- 3. 如果同时按下了 Shift 键,则还原为默认的 box 类样式 -->
<div class="box" :class="shape"
     @click.ctrl="changeShape('square')"
     @click.alt="changeShape('round')"
     @click.shift="changeShape('')">
</div>

对应的 JS 逻辑为:

const app = createApp({
  data() {
    return {
      // 类样式的名称
      shape: ''
    }
  },
  methods: {
    // 事件的处理函数
    changeShape(shape) {
      this.shape = shape
    }
  }
})

对应的 CSS 样式为:

<style>
  .box {
    width: 300px;
    height: 300px;
    background-color: #efefef;
    transition: all 1s ease;
  }

  .square {
    border-radius: 20px;
    background-color: cyan;
    transition: all 1s ease;
  }

  .round {
    border-radius: 50%;
    background-color: lightgreen;
    transition: all 1s ease;
  }
</style>

k. .exact 修饰符

上述的例子中,存在一个很明显的 Bug:

  • 我们希望在触发 div 的 click 事件时,仅当用户按下了 Ctrl 或 Alt 或 Shift 按键时,才触发 changeShape 函数
  • 现在的 Bug 是,用户在触发 click 事件时,如果按下了 Ctrl + Alt 的组合按键,也会触发 changeShape 函数

而 .exact 修饰符可以完美的解决这个问题。.exact 修饰符表示精确匹配系统按键。

因此,我们可以针对上述的例子进行修改,在特定的系统按键修饰符的后面应用 .exact 修饰符,表示精确匹配系统按键:

<div class="box" :class="shape" 
     @click.ctrl.exact="changeShape('square')" 
     @click.alt.exact="changeShape('round')"
     @click.shift.exact="changeShape('')">
</div>

注意:所谓的精确匹配系统按键,仅对系统按键修饰符生效,如果用户按下了 Ctrl + A 的组合键,也会触发 @click.ctrl.exact 所绑定的事件处理器。

k.鼠标按键修饰符

vue 还提供了鼠标按键修饰符,用来监听事件是否由特定的鼠标按键触发:

  • .left
  • .right
  • .middle

例如,下面的代码演示了如何阻止在 h1 元素上显示鼠标的右键菜单

<h1 @click.right.prevent>这是一个标题</h1>

注意:绑定事件时,不一定非要提供事件的处理器,我们也可只提供事件修饰符,从而达到特定的目的。

6. 列表渲染指令

v-for 指令是 vue 提供的列表渲染指令。

如果您有一个数组,想把数组中的每一项渲染为格式相似的 HTML 结构,那么 v-for 指令可以帮助您实现列表数据的渲染。

使用场景:商品列表、用户列表等。

a. v-for 的基本使用

v-for 的基本语法格式为:

v-for="当前循环项 in 数组"

其中关键字 in 前面的是当前循环项,关键字 in 后面的要循环的数组。例如:

<ul>
  <li v-for="item in list">姓名:{{ item.name }},年龄:{{ item.age }}</li>
</ul>

对应的数据为:

const app = createApp({
  data() {
    return {
      // 数组
      list: [
        { name: 'zs', age: 20 },
        { name: 'ls', age: 21 },
        { name: 'wp', age: 22 }
      ]
    }
  }
})

b.v-for 中的索引

v-for 的完整语法格式为:

v-for="(循环项, 循环项的索引) in 数组"

其中 in 关键字左侧的 ( ) 里面,分别是当前循环项当前循环项的索引。例如:

<ul>
  <li v-for="(item, index) in goods">{{ index + 1 }}. {{ item }}</li>
</ul>

对应的数据为

const app = createApp({
  data() {
    return {
      // 数组
      goods: ['手表', '手机', '手串']
    }
  }
})

注意:v-for 中的索从 0 开始递增。

c.v-for 中的解构

如果 v-for 指令中的循环项 item 是一个对象,则可以在 v-for 指令中进行解构操作,语法格式为:

v-for="{数据A, 数据B} in 数组"
或
v-for="({数据A, 数据B}, 索引) in 数组"

其中 in 关键字左侧的 { } 表示解构操作。例如:

<ul>
  <li v-for="{name, age} in list">姓名:{{ name }},年龄:{{ age }}</li>
</ul>

对应的数据为:

const app = createApp({
  data() {
    return {
      // 数组
      list: [
        { name: 'zs', age: 20 },
        { name: 'ls', age: 21 },
        { name: 'wp', age: 22 }
      ]
    }
  }
})

d.template 上的 v-for

v-for 指令每次只能循环生成一个元素,如果想在每次循环期间生成一组元素,则必须在这一组元素之外包裹一层 div 标签作为容器,并把 v-for 指令作用于外层的 div 容器之上。例如:

<ul>
  <div v-for="(item, index) in list">
    <li class="divider" v-if="index!== 0"></li>
    <li>姓名:{{ item.name }},年龄:{{ item.age }}</li>
  </div>
</ul>

对应的 css 样式为:

<style>
  .divider {
    border-top: 1px solid #888;
    list-style: none;
    margin: 10px 0;
  }
</style>

如上,虽然可以实现列表数据的渲染,但却不尽完美。因为 div 标签在循环中只起到容器的作用,在整个列表结构中没有任何意义。

所以推荐的做法是利用 vue 内置的 <template> 标签替代上述的 div 标签,因为 <template> 是一个虚拟的容器不会被渲染为实际的元素

最终,优化过后的代码如下:

<ul>
  <template v-for="(item, index) in list">
    <li class="divider" v-if="index!== 0"></li>
    <li>姓名:{{ item.name }},年龄:{{ item.age }}</li>
  </template>
</ul>

e.v-for 与 v-if 的优先级

注意:vue 官方不推荐在一个元素上,同时使用 v-if 和 v-for 指令。因为这样使用无法明确体现出二者的优先级。降低代码的阅读性和维护性。

当 v-if 和 v-for 同时存在于一个元素上的时候,v-if 比 v-for 的优先级更高。这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名:

<ul>
  <!-- 注意:这里的 v-if 指令中,无法访问到 item.done 对应的数据, -->
  <!-- 因为 v-if 比 v-for 的优先级高, -->
  <!-- 当 v-if 执行的时候访问不到 item 对象,因为 v-for 此时还未执行! -->
  <li v-for="item in todos" v-if="!item.done">{{item.task}}</li>
</ul>

对应的数据为:

const app = createApp({
  data() {
    return {
      // 任务列表,done 为 true 表示完成;done 为 false 表示未完成
      todos: [
        { task: '晨练', done: true },
        { task: '吃早餐', done: true },
        { task: '吃午饭', done: false },
        { task: '午休', done: false }
      ]
    }
  }
})

解决的方案很简单,先循环再判断即可。在 li 元素的外层包裹一个 template 组件,并把 v-for 指令从 li 上挪到 template 组件上,示例代码如下:

<ul>
  <template v-for="item in todos">
    <li v-if="!item.done">{{item.task}}</li>
  </template>
</ul>

改造后的代码除了解决了 v-if 优先级高导致的报错问题之外,还有这3个明显的特征:

1.<template> 是一个虚拟容器,不会被渲染为任何实际元素,因此不会导致 DOM 结构的冗余

2.代码的可读性更强,外层用来循环数组从而得到每个列表项,内部根据列表项的状态实现 DOM 结构的按需渲染

3.如果 item.done 值为 false,则不会渲染对应的 DOM 结构,因此初始的渲染性能较好

标签:常用,createApp,app,绑定,指令,Vue3,const,data
From: https://blog.51cto.com/u_12849855/7597264

相关文章

  • java项目开发常用配置文件模板
    mybatisconfig文件1<?xmlversion="1.0"encoding="UTF-8"?>2<!DOCTYPEconfiguration3PUBLIC"-//mybatis.org//DTDConfig3.0//EN"4"http://mybatis.org/dtd/mybatis-3-config.dtd">5......
  • ES常用查询命令
    一、基本命令1获取所有_cat命令curl-XGETlocalhost:9200/_cat2获取es集群服务健康状态3查看es节点信息4查看es指定节点信息二、索引操作查看ES中所有的索引新建索引删除索引查看指定索引信息查看索引的统计信息三、文档操作*3.1查询索引中的全部文档3.2......
  • 使用SpringBoot+Vue3的形式实现管理系统的添加功能
    1、查看页面形式2、使用element-plus组件为添加页面引入form表单成功引入form表单组件:3、更改成自己需要的形式4、测试是否可以拿到文本框的数据拿到数据啦!!(记得vue3这里:console.log(form)//不要写this```)#5、vue界面的添加代码<el-form-item>......
  • 常用词汇(英)
    CodeForces/Atcoder常用词汇(英),俄我也不会AT:Atcoder,CF:Codeforces-permutation排列-initially初始地-integers整数-elements元素-obtain获取,取得-lexicographical(ly)字典序(地)-[CF]correspond(ing)对应-[AT]denote代表,对应-exceed超过,......
  • layer 经常用的一些方法
    //删除确认functionm_del(id){layer.confirm('确认删除?',{btn:['确认','取消'],},function(index,layero){$.ajax({type:"POST",url:durl,data:{'id':id},success:function(data){if(data.Success){layer.ale......
  • mysql常用函数
    1、AVG():返回平均值2、COUNT():返回行数3、FIRST():返回第一个记录的值4、LAST():返回最后一个记录的值5、MAX():返回最大值6、MIN():返回最小值7、SUM():返回总和8、UCASE():将某个字段转换为大写9、LCASE():将某个字段转换为小写12、ROUND():对某个数值字段进行指定小数位数的四......
  • Redis常用操作命令
     关于Redis的操作命令实在是太多了,我们不可能每个都说,用的时候查找即可,现在只简单说明一下1.对键操作的命令exists(key):确认一个key是否存在del(key):删除一个keytype(key):返回值的类型keys(pattern):返回满足给定pattern的所有keyrandomkey:随机返回key空间的一个keyrename(o......
  • 线程一些常用功能总结
    c++11通常单例模式如下:template<typenameT>classSingleton{protected:Singleton()=default;Singleton(constSingleton<T>&)=delete;Singleton&operator=(constSingleton<T>&st)=delete;staticstd::shared_ptr&......
  • 《架构即未来》中最常用的15个架构原则
    《架构即未来》这本书的第12章简单阐述了架构设计的一些常用的原则(后面章节会详细阐述)。这些原则中很多都是在架构一开始的设计中就要考虑进去的,这样在出现任何问题时,我们都能够及时的处理,和把问题影响的范围有效的缩小。否则就像我现在的项目,一开始设计时,考虑的很少,出问题时,没有做......
  • Windbg常用命令及分析套路
    自己也在使用windbg分析问题,但是属于刚入门所以转发下大神的总结:https://www.cnblogs.com/fj365/p/13295453.html常用!threadpool查看线程池CPU使用量!threads查看所有托管线程情况!clrstack某个线程托管代码的调用......