• Vue的基础语法-常用v-on、v-if、v-bind等指令的细节(最详细)


    模板语法

    React的开发模式

    • React使用的jsx,所以对应的代码都是编写的类似于js的一种语法

    • 之后通过Babel将jsx编译成 React.createElement 函数调用;

    Vue也支持jsx的开发模式

    • 但是大多数情况下,使用基于HTML的模板语法

    • 在模板中,允许开发者以声明式的方式将DOM和底层组件实例的数据绑定在一起

    • 在底层的实现中,Vue将模板编译成虚拟DOM渲染函数,这个我会在后续给大家讲到;

    所以,对于学习Vue来说,学习模板语法是非常重要的

    Mustache语法

    如果我们希望把数据显示到模板(template)中,使用最多的语法是“Mustache”语法 (双大括号) 的文本插值。

    • 并且我们前端提到过,data返回的对象是有添加到Vue的响应式系统中;
    • data中的数据发生改变时,对应的内容也会发生更新
    • 当然,Mustache中不仅仅可以是data中的属性,也可以是一个JavaScript的表达式, 甚至是一个三元运算符, 调用函数

    基本使用:

    <div id="app">
      
      <h2>{{ message }}h2>
      <h2>当前计数: {{ counter }}h2>
    div>
    
    
    <script src="../js/vue.js">script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            message: "Hello Vue",
            counter: 1,
          };
        },
      });
    
      app.mount("#app");
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    js表达式:

    <div id="app">
      
      <h2>计数双倍:{{ counter * 2 }}h2>
      <h2>展示的信息:{{ info.split(" ") }}h2>
    div>
    
    
    <script src="../js/vue.js">script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            message: "Hello Vue",
            counter: 1,
            info: "Hello Vue3"
          };
        },
      });
    
      app.mount("#app");
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    三元表达式:

    <div id="app">
      
      <h2>{{ age >= 18? "成年人": "未成年" }}h2>
    div>
    
    
    <script src="../js/vue.js">script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            message: "Hello Vue",
            counter: 0,
            info: "Hello Vue3",
            age: 18
          };
        },
      });
    
      app.mount("#app");
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    Mustache调用函数:

    <div id="app">
      <!-- 4.调用函数 -->
      <h2>{{ sum(10, 20) }}</h2>
    </div>
    
    <!-- 从本地引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            message: "Hello Vue",
            counter: 0,
            info: "Hello Vue3",
            age: 18,
          };
        },
        methods: {
          sum(num1, num2) {
            return num1 + num2;
          },
        },
      });
    
      app.mount("#app");
    </script
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    另外以下用法是错误的

    
    
    <h2>{{ var name = "Hello Vue3" }}h2>
    
    <h2>{{ if (true) {return message} }}h2>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    不常用基本指令

    以下指令实际运用场景很少, 我们了解一下即可

    v-once指令(了解)

    v-once用于指定元素或者组件只渲染一次

    • 当数据发生变化时,元素或者组件以及其所有的子元素将视为静态内容并且跳过;

    • 该指令可以用于性能优化

    如下, 正常点击按钮会改变message, 而加上v-once后页面就不会改变, 因为只渲染一次

    • 其实message的值是改变了的, 只是不会渲染
    <div id="app">
      <h2 v-once>{{ message }}h2>
      <button @click="change">改变messgebutton>
    div>
    
    
    <script src="../js/vue.js">script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            message: "Hello Vue",
          };
        },
        methods: {
          change() {
            this.message = "你好 Vue3";
          },
        },
      });
    
      app.mount("#app");
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    不仅是绑定了v-once的元素只渲染一次, 绑定了v-once元素的子元素同样也是只会渲染一次

    v-text指令(了解)

    用于更新元素的 textContent :

    <div id="app">
      <h2>{{ message }}h2>
      
      <h2 v-text="message">h2>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    由于Mustache插值语法更灵活, 所以我们一般使用插值语法, v-text很少使用

    v-html指令(了解)

    v-html偶尔会用到, 某些特殊场景

    默认情况下,如果我们展示的内容本身是 html 的,那么vue并不会对其进行特殊的解析

    <div id="app">
      <h2>{{ content }}h2>
    div>
    
    
    <script src="../js/vue.js">script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            content: `Hello Vue`,
          };
        },
      });
    
      app.mount("#app");
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 展示内容原封不动

    在这里插入图片描述

    如果我们希望这个内容被Vue可以解析出来,那么可以使用 v-html 来展示

    <div id="app">
      
      <h2 v-html="content">h2>
    div>
    
    
    <script src="../js/vue.js">script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            content: `Hello Vue`,
          };
        },
      });
    
      app.mount("#app");
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    v-pre指令(了解)

    v-pre用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签

    • 跳过不需要编译的节点,加快编译的速度;
    <div id="app">
      
      <h2 v-pre>
        {{ message }}
        
        <span>{{ message }}span>
      h2>
    div>
    
    
    <script src="../js/vue.js">script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            message: "Hello Vue",
          };
        },
      });
    
      app.mount("#app");
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    重点掌握的指令

    以下指令在我们开发中会频繁使用, 需要重点掌握

    v-bind指令

    1.介绍(了解)

    v-bind指令是帮助我们动态绑定属性的

    **前面讲的一系列指令,主要是将值插入到模板内容**中。

    但是,除了内容需要动态来决定外,某些属性我们也希望动态来绑定

    • 比如动态绑定a元素的href属性;
    • 比如动态绑定img元素的src属性;

    绑定属性我们使用v-bind( 以下是官方对v-bind的描述, 看不懂了解即可, 很多东西我们都是用不上的 ):

    缩写:

    预期:any (with argument) | Object (without argument)

    参数:attrOrProp (optional)

    修饰符:.camel - 将 kebab-case attribute 名转换为 camelCase。

    用法:动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。


    2.绑定基本的属性

    v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值(这个学到组件时再介绍)

    在开发中,有哪些属性需要动态进行绑定呢?

    • 还是有很多的,比如图片的链接src、网站的链接href、动态绑定一些类、样式等等

    v-bind有一个对应的语法糖: :代替v-bind,也就是简写方式。

    • 在开发中,我们通常会使用语法糖的形式,因为这样更加简洁。
    <div id="app">
      
      
      <img v-bind:src="imgUrl" alt="" />
      
      <img :src="imgUrl" alt="" />
    
      
      
      <a v-bind:href="aHref">百度一下a>
      
      <a :href="aHref">百度一下a>
    div>
    
    
    <script src="../js/vue.js">script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            imgUrl:
              "https://res.vmallres.com/uomcdn/CN/cms/202207/3466E7368238FF1C17CA6C074D9C3BAD.png.webp",
            aHref: "https://www.baidu.com",
          };
        },
      });
    
      app.mount("#app");
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    3.绑定class属性

    在开发中,有时候我们的元素class也是动态的,比如

    • 当数据为某个状态时,字体显示红色。
    • 当数据另一个状态时,字体显示黑色。

    绑定class有两种方式

    • 对象语法

    • 数组语法

    方式一: 对象语法

    对象语法: 我们可以传给 :class (v-bind:class 的简写) 一个对象,以动态地切换 class。

    • 语法: :class={要绑定的类名: 布尔值}布尔值为true绑定, 为false不绑定

    例如我们有如下一个需求: 当点击按钮时, 文字变成红色, 再次点击恢复默认色

    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Documenttitle>
    
        <style>
          .active {
            color: red;
          }
        style>
      head>
      <body>
        <div id="app">
          
          <button :class="{ active: isFlag }" @click="changeColor">按钮button>
        div>
    
        
        <script src="../js/vue.js">script>
        <script>
          const app = Vue.createApp({
            data() {
              return {
                isFlag: false,
              };
            },
            methods: {
              changeColor() {
                this.isFlag = !this.isFlag;
              },
            },
          });
    
          app.mount("#app");
        script>
      body>
    html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    对象语法注意事项:

    • 对象语法也是可加多个键值对的, 绑定多个class; 逗号分开即可
    <button :class="{ active: isFlag, aaa: true, bbb: true }">按钮button>
    
    • 1
    • 动态绑定的class是可以和普通的class共存的
    <button class="ccc" :class="{ aaa: true, bbb: true }">按钮button>
    
    • 1
    • 动态绑定class是可以调用函数的, 我们可以将对象放入一个函数中, 调用函数返回一个对象
    <div id="app">
      
      <button :class="classFn()" @click="changeColor">按钮button>
    div>
    
    
    <script src="../js/vue.js">script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            isFlag: false,
          };
        },
        methods: {
          changeColor() {
            this.isFlag = !this.isFlag;
          },
          classFn() {
            return { active: this.isFlag, aaa: true, bbb: true };
          },
        },
      });
    
      app.mount("#app");
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    方式二: 数组语法(了解)

    数组语法: 我们可以把一个数组传给 :class,以应用一个 class 列表;

    数组语法用的相对较少, 我们简单演练一下

    <div id="app">>
      <!-- 动态绑定数组语法 -->
      <!-- 1.基本使用 -->
      <h2 :class="['aaa', 'bbb']">Hello Vue</h2>
      <!-- 2.数组中存放变量 -->
      <h2 :class="[className1, className2]">Hello Vue</h2>
      <!-- 3.数组中放一个对象语法 -->
      <h2 :class="['aaa', { active: isFlag }]">Hello Vue </h2>
    </div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.绑定style属性

    我们可以利用v-bind:style来绑定一些CSS内联样式

    • 这是因为某些样式我们需要根据数据动态来决定
    • 比如某段文字的颜色,大小等等;

    CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名;

    绑定class有两种方式

    • 对象语法

    • 数组语法


    对象语法演练:

    <div id="app">
      
      <h2 :style="{ color: 'red', fontSize: '30px'}">{{ message }}h2>
      
      <h2 :style="{ color: color, fontSize: size}">{{ message }}h2>
      
      <h2 :style="styleObj">{{ message }}h2>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    数组语法演练:

    • :style 的数组语法可以将多个样式对象应用到同一个元素上;
    <div id="app">
      
      <h2 :style="[styleObj1, styleObj2]">{{ message }}h2>
    
    • 1
    • 2
    • 3
    • 4

    5.动态绑定属性名(了解)

    在某些情况下,我们属性的名称可能也不是固定

    • 前端我们无论绑定src、href、class、style,属性名称都是固定的;

    • 如果属性名称不是固定的,我们可以使用 :[属性名]=“值” 的格式来定义;

    这种绑定的方式,我们称之为动态绑定属性

    <div id="app">
    	
    	<h2 :[name]="'aaa'">{{ message }}h2>
    div>
    
    • 1
    • 2
    • 3
    • 4

    6.绑定一个对象

    常用于组件传值, 非常有用

    如果我们希望将一个对象的所有属性,绑定到元素上的所有属性,应该怎么做呢?(做到如下效果)

    <div id="app">
      <h2 :name="name" :age="age" height="height">{{ message }}h2>
    div>
    
    • 1
    • 2
    • 3

    非常简单,我们可以直接使用 v-bind 绑定一个 对象

    <div id="app">
      <h2 :name="name" :age="age" height="height">{{ message }}h2>
    
      
      <h2 v-bind="infos">h2>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    v-on指令

    v-on绑定事件, 用于交互

    前面我们绑定了元素的内容和属性,在前端开发中另外一个非常重要的特性就是交互

    在前端开发中,我们需要经常和用户进行各种各样的交互

    • 这个时候,我们就必须监听用户发生的事件,比如点击、拖拽、键盘事件等等

    • 在Vue中如何监听事件呢?使用v-on指令。

    接下来我们来看一下v-on的用法


    1.v-on基本使用

    v-on的使用( 同样以下是官方对v-bind的描述, 看不懂了解即可 ):

    缩写@

    预期:Function | Inline Statement | Object

    参数:event

    修饰符

    • .stop - 调用 event.stopPropagation()。

    • .prevent - 调用 event.preventDefault()。

    • .capture - 添加事件侦听器时使用 capture 模式。

    • .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。

    • .{keyAlias} - 仅当事件是从特定键触发时才触发回调。

    • .once - 只触发一次回调。

    • .left - 只当点击鼠标左键时触发。

    • .right - 只当点击鼠标右键时触发。

    • .middle - 只当点击鼠标中键时触发。

    • .passive - { passive: true } 模式添加侦听器

    用法:绑定事件监听


    下面我们演练一下v-on的基本使用

    • 我们可以使用v-on来监听一下点击的事件:
    
    <div class="box" v-on:click="divBtn">div>
    
    • 1
    • 2
    • v-on:click可以写成@click,是它的语法糖写法
    
    <div class="box" @click="divBtn">div>
    
    • 1
    • 2
    • 绑定方法的位置可以传入一个表达式, (不常用不推荐):
    <h2>{{ counter }}h2>
    
    <button @click="counter++">+button>
    <button @click="counter--">-button>
    
    • 1
    • 2
    • 3
    • 4
    • 当然只是可以绑定点击事件,我们也可以绑定其他的事件
    
    <div class="box" @mousemove="divMove">div>
    
    • 1
    • 2
    • 元素也可以绑定多个事件(相对下面的写法更推荐 ):
    
    <div class="box" @click="divBtn" @mousemove="divMove">div>
    
    • 1
    • 2
    • 元素绑定多个事件,这个时候其实可以传入一个对象
    
    <div class="box" v-on="{ click: divBtn, mousemove: divMove }">div>
    
    • 1
    • 2

    2.v-on参数传递

    当通过methods中定义方法,以供@click调用时,需要注意参数问题

    情况一:如果该方法不需要额外参数,那么方法后的()可以不添加

    • 但是注意:如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去

    情况二:如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件


    演示代码:

    <div id="app">
      
      <button @click="btn1Click">按钮1button>
      
      <button @click="btn2Click('kaisa', 18, 1.88)">按钮2button>
      
      <button @click="btn3Click('kaisa', 18, 1.88, $event)">按钮3button>
    div>
    
    
    <script src="../js/vue.js">script>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            message: "Hello Vue",
          };
        },
        methods: {
          // 1.默认参数: 是event对象
          // 在绑定对象的时, 如果没有传递任何参数, 那么event对象默认传递进来
          btn1Click(event) {
            console.log("btn1:", event);
          },
    
          // 2.明确的传入参数, 会将event覆盖掉
          btn2Click(name, age, height) {
            console.log("btn2:", name, age, height);
          },
    
          // 3.明确的参数 + event对象
          btn3Click(name, age, height) {
            console.log("btn3:", name, age, height, event);
          },
        },
      });
    
      app.mount("#app");
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    3.v-on的修饰符

    v-on支持修饰符,修饰符相当于对事件进行了一些特殊的处理(了解)

    • .stop - 相当于调用 event.stopPropagation(), 阻止冒泡
    <div id="app">
      <div class="box" @click="divClick">
        
        <button @click.stop="btnClick">按钮button>
      div>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • .prevent - 相当于调用 event.preventDefault(), 阻止默认行为。
    • .capture - 添加事件侦听器时使用 capture 模式。
    • .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
    • .{keyAlias} - 仅当事件是从特定键触发时才触发回调。
    • .once - 只触发一次回调。
    • .left - 只当点击鼠标左键时触发。
    • .right - 只当点击鼠标右键时触发。
    • .middle - 只当点击鼠标中键时触发。
    • .passive - { passive: true } 模式添加侦听器

    条件渲染指令

    在某些情况下,我们需要根据当前的条件决定某些元素或组件是否渲染,这个时候我们就需要进行条件判断了

    Vue提供了下面的指令来进行条件判断

    • v-if

    • v-else

    • v-else-if

    • v-show

    下面我们来对它们进行学习


    1.v-if、v-else、v-else-if

    v-if、v-else、v-else-if用于根据条件来渲染某一块的内容

    • 这些内容只有在条件为true时,才会被渲染出来

    • 这三个指令与JavaScript的条件语句if、else、else if类似

    例如我们有如下案例, 当成绩不同时, 在页面上显式不同的元素

    <div id="app">
      <h2 v-if="score > 90">优秀h2>
      <h2 v-else-if="score >= 70">良好h2>
      <h2 v-else-if="score >= 60">及格h2>
      <h2 v-else>不及格h2>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    v-if的渲染原理

    • v-if是惰性的;

    • 当条件为false时,其判断的内容完全不会被渲染或者会被销毁掉;

    • 当条件为true时,才会真正渲染条件块中的内容;

    2.template元素

    这个元素时Vue3出现的, 解决了Vue2只能包裹div的痛点

    因为v-if是一个指令,所以必须将其添加到一个元素上

    • 但是如果我们希望切换的是多个元素呢?

    • 此时我们一般会包裹一个div,但是我们并不希望div这种元素被渲染;

    • 这个时候,我们可以选择使用template;

    <div id="app">
      <template v-if="isShow">
        <h2>{{ message }}h2>
        <h2>{{ message }}h2>
        <h2>{{ message }}h2>
        <h2>{{ message }}h2>
      template>
    
      <template v-else>
        <h2>哈哈哈哈h2>
        <h2>哈哈哈哈h2>
        <h2>哈哈哈哈h2>
        <h2>哈哈哈哈h2>
      template>
    
      <button @click="btnClick">切换button>
    div>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    template元素可以当做不可见的包裹元素,并且在v-if上使用,但是最终template不会被渲染出来

    • 小程序中的block也是类似这种

    3.v-show指令

    v-show和v-if的用法看起来是一致的,也是根据一个条件决定是否显示元素或者组件

    <div id="app">
      <h2 v-show="isShow">{{ message }}h2>
    div>
    
    • 1
    • 2
    • 3

    那么v-show和v-if有什么区别呢?

    首先,在用法上的区别:

    • v-show是不支持template

    • v-show不可以和v-else或v-else-if一起使用

    其次,本质的区别:

    • v-show元素无论是否需要显示到浏览器上,它的DOM实际都是有存在的,只是通过CSS的display属性来进行切换

    • v-if当条件为false时,其对应的原生压根不会被渲染到DOM中;

    开发中如何进行选择呢?

    • 如果我们的元素需要在显示和隐藏之间频繁的切换,那么使用v-show

    • 如果不会频繁的发生切换font>,那么使用v-if

    v-for指令

    1.v-for遍历数组

    在真实开发中,我们往往会从服务器拿到一组数据,并且需要对其进行渲染

    • 这个时候我们可以使用v-for来完成;

    • v-for类似于JavaScript的for循环,可以用于遍历一组数据;

    v-for的基本格式是 item in 数组

    • 数组通常是来自data或者prop,也可以是其他方式;

    • item是我们给每项元素起的一个别名,这个别名可以自定来定义;

    我们知道,在遍历一个数组的时候会经常需要拿到数组的索引font>

    • 如果我们需要索引,可以使用格式: (item, index) in 数组

    • 注意上面的顺序:数组元素项item是在前面的,索引项index是在后面的;


    遍历数组简单数据

    • 例如我们有如下一个电影名称的数组, 我们来演示一下v-for如何遍历:
    movies: ["大话西游", "赌圣", "蝙蝠侠", "羞羞的铁拳", "哥谭"]
    
    • 1
    • 只遍历展示数组中的每一个元素, 不需要索引
    <ul>
      <li v-for="item in movies">{{ item }}li>
    ul>
    
    • 1
    • 2
    • 3
    • 当遍历中需要索引
    <ul>
      <li v-for="(item, index) in movies">{{ index }} : {{ item }}li>
    ul>
    
    • 1
    • 2
    • 3

    遍历数组复杂数组

    实际开发中, 我们遍历的不仅是一个简单的数组, 而是类似于下面的数组, 这种其实才是最常见的

    • 遍历如下数组内容
    persons: [
      { name: "kaisa", age: 18, hobby: "唱" },
      { name: "vn", age: 20, hobby: "跳" },
      { name: "liqin", age: 21, hobby: "rap" },
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    <div class="box" v-for="item in persons">
      <h2>名字: {{ item.name }}h2>
      <h2>年龄: {{ item.age }}h2>
      <h2>爱好: {{ item.hobby }}h2>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.v-for其他类型

    v-for也支持遍历对象,并且支持有一二三个参数

    • 一个参数: 遍历的是value, value in object;

    • 二个参数:遍历的是value和key, (value, key) in object;

    • 三个参数: 遍历的是value, key和index(value, key, index) in object;

    
    <ul>
      <li v-for="value in infos">{{ value }}li>
    ul>
    
    
    <ul>
      <li v-for="(value, key) in infos">{{ value }}-{{ key }}li>
    ul>
    
    
    <ul>
      <li v-for="(value, key, index) in infos">{{ value }}-{{ key }}-{{index}}li>
    ul>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    v-for也可以遍历字符串, 字符串也是可迭代对象

    
    <ul>
      <li v-for="item in message">{{ item }}li>
    ul>
    
    • 1
    • 2
    • 3
    • 4

    v-for同时也支持数字的遍历

    • 每一个item都是一个数字, 会依次赋值;
    
    <ul>
      <li v-for="item in 10">{{ item }}li>
    ul>
    
    • 1
    • 2
    • 3
    • 4

    v-for可迭代对象(Iterable)都可以通过v-for遍历


    3.template元素

    类似于v-if,你可以使用 template 元素来循环渲染一段包含多个元素的内容

    • 我们使用template来对多个元素进行包裹,而不是使用div来完成, 前提是真的不需要, div是无意义的时候使用;
    <template v-for="(value, key, index) in infos">
      <span>{{ value }}span>
      <strong>{{ key }}strong>
      <i>{{ index }}i>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.v-for中的key

    在使用v-for进行列表渲染时,我们通常会给元素或者组件绑定一个key属性

    • 而这个key通常又是唯一的, 我们经常使用v-bind动态绑定
    
    <ul>
      <li v-for="item in letters" :key="item">{{ item }}li>
    ul>
    
    • 1
    • 2
    • 3
    • 4

    这个key属性有什么作用呢?我们先来看一下官方的解释

    • key属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes

    • 如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法;

    • 使用key时,它会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素;

    官方的解释对于初学者来说并不好理解,比如下面的问题

    • 什么是新旧nodes,什么是VNode?

    • 没有key的时候,如何尝试修改和复用的?

    • key的时候,如何基于key重新排列的?

    下面我们来解释一下

    4.1认识VNode

    在Vue中, 我们HTML元素其实并不会直接被渲染成DOM, 在HTML渲染成DOM中间还有一个环节就是VNode

    在这里插入图片描述

    我们先来解释一下VNode的概念

    • 因为目前我们还没有比较完整的学习组件的概念,所以目前我们先理解HTML元素创建出来的VNode

    • VNode的全称是Virtual Node,也就是虚拟节点

    • 事实上,无论是组件还是元素,它们最终在Vue中表示出来的都是一个个VNode, 每一个元素都会创建一个VNode

    • VNode的本质是一个JavaScript的对象

    例如我们有如下一个HTML元素:

    <div class="title" style="font-size: 30px; color: red;">哈哈哈div>
    
    • 1

    这个div元素创建出来的VNode是下面这样的:

    const vnode = {
      type: "div",
      props: {
        class: "title",
        style: {
          "font-size": "30px",
          color: "red",
        },
      },
      children: "哈哈哈",
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    4.2虚拟DOM

    如果我们不只是一个简单的div,而是有一大堆的元素相互嵌套,而这每一个元素都会创建一个VNode , 那么多个VNode直接应该会形成一个VNode Tree

    • 这个形成的VNode Tree 就是虚拟DOM(Virtual DOM)

    在这里插入图片描述

    5.key的作用

    上面给大家铺垫了两个重要的概念, 那么我们说回来, key到底是什么作用

    例如下面代码中, 我们想要在中间插入一个 f

    在这里插入图片描述

    我们可以确定的是,这次更新对于ul和button是不需要进行更新,需要更新的是我们li的列表

    • 在Vue中,对于相同父元素的子元素节点并不会重新渲染整个列表;

    • 因为对于列表中 a、b、c、d它们都是没有变化的;

    • 在操作真实DOM的时候,我们只需要在中间插入一个f的li即可

    那么Vue中对于上面列表的情况, 更新究竟是如何操作的呢?

    • Vue事实上会对于有key和没有key会调用两个不同的方法;

    • 有key,那么就使用 patchKeyedChildren方法

    • 没有key,那么就使用 patchUnkeyedChildren方法

    那么这两个方法有什么不同呢?


    没有key的diff算法

    在这里插入图片描述

    我们会发现上面的diff算法效率并不高

    • c和d来说它们事实上并不需要有任何的改动;

    • 但是因为我们的 c 被 f 所使用了,所以后续所有的内容都要一次进行改动,并且最后进行新增;


    有key的diff算法

    第一步的操作是从头开始进行遍历、比较

    • a和b是一致的会继续进行比较;

    • c和f因为key不一致,所以就会break跳出循环;

    在这里插入图片描述

    第二步的操作是从尾部开始进行遍历、比较

    • c和d是一致的会继续进行比较;
    • b和f因为key不一致, 所一会跳出循环

    在这里插入图片描述

    第三步是如果旧节点遍历完毕,但是依然有新的节点,那么就新增节点

    在这里插入图片描述

    第四步是如果新的节点遍历完毕,但是依然有旧的节点,那么就移除旧节点

    在这里插入图片描述

    第五步是最特殊的情况,中间还有很多未知的或者乱序的节点

    • 乱序也会尽量复用节点

    在这里插入图片描述

    所以我们可以发现,Vue在进行diff算法的时候,会尽量利用我们的key来进行优化操作

    • 没有key的时候我们的效率是非常低效的;

    • 在进行插入或者重置顺序的时候,保持相同的key可以让diff算法更加的高效;

  • 相关阅读:
    CF1899B 250 Thousand Tons of TNT
    独立站卖家在哪些平台做社交媒体营销效果最好?
    【Linux】TCP的服务端(守护进程) + 客户端
    【前端三栏布局总结】常见的前端三栏布局有哪些
    【Electron】vue+electron应用设置菜单
    进击!BERT句向量表征
    【代码管理】Git删除仓库中的大文件压缩仓库大小
    深入理解计算机系统——第八章 Exceptional Control Flow
    MySQL如何记忆
    vue3项目搭建手册
  • 原文地址:https://blog.csdn.net/m0_71485750/article/details/125791207