Vue模板语法+双大括号语法;Vue常见的基本指令(v-once、v-text、v-pre、v-memo等);v-bind绑定属性;v-on绑定事件;Vue的条件渲染;v-for;虚拟DOM

1_Mustache语法

1.1_模板语法

React的开发模式:

  • React使用的jsx,所以对应的代码都是编写的类似于js的一种语法;
  • 之后通过Babel将jsx编译成 React.createElement 函数调用;

Vue也支持jsx的开发模式:

  • 但是大多数情况下,使用基于HTML的模板语法;
  • 在模板中,允许开发者以声明式的方式将DOM和底层组件实例的数据绑定在一起;
  • 在底层的实现中,Vue将模板编译成虚拟DOM渲染函数

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

1.2_双大括号语法

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

  • 并且前端提到过,data返回的对象是有添加到Vue的响应式系统中;
  • 当data中的数据发生改变时,对应的内容也会发生更新。
  • 当然,Mustache中不仅仅可以是data中的属性,也可以是一个JavaScript的表达式。
<body>

  <div id="app">
    <!-- 1.基本使用 -->
    <h2>{
   
   { message }}</h2>
    <h2>当前计数: {
   
   { counter }} </h2>

    <!-- 2.表达式 -->
    <h2>计数双倍: {
   
   { counter * 2 }}</h2>
    <h2>展示的信息: {
   
   { info.split(" ") }}</h2>

    <!-- 3.三元运算符 -->
    <h2>{
   
   { age >= 18? "成年人": "未成年人" }}</h2>

    <!-- 4.调用methods中函数 -->
    <h2>{
   
   { formatDate(time) }}</h2>

    <!-- 5.注意: 这里不能定义语句 -->
    <!-- <h2>{
    
    { const name = "xxx" }}</h2> -->

  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data: function() {
      
      
        return {
      
      
          message: "Hello Vue",
          counter: 100,
          info: "my name is hhh",
          age: 22,
          time: 123
        }
      },
      methods: {
      
      
        formatDate: function(date) {
      
      
          return "2035-10-10-" + date
        }
      }
    })
    // 2.挂载app
    app.mount("#app")
  </script>
</body> 



2_常见的基本指令

2.1_v-once指令

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

  • 当数据发生变化时,元素或者组件以及其所有的子元素将视为静态内容并且跳过;
  • 该指令可以用于性能优化;
  • 如果是子节点,也只渲染一次:
<body>

  <div id="app">
    <!-- 指令: v-once -->
    <h2 v-once>
      {
    
    {
    
     message }}
      <span>数字: {
    
    {
    
    counter}}</span>
    </h2>
     <!-- 没有指令 -->
    <h1>{
    
    {
    
    message}}</h1>
    <h1>{
    
    {
    
    counter}}</h1>

    <button @click="changeMessage">改变message</button>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
    
    
      // data: option api
      data: function() {
    
    
        return {
    
    
          message: "Hello Vue",
          counter: 100
        }
      },
      methods: {
    
    
        changeMessage: function() {
    
    
          this.message = "你好啊, 李银河"
          this.counter += 100
          console.log(this.message, this.counter)
        }
      }
    })
    // 2.挂载app
    app.mount("#app")
  </script>
</body>

如下图所示,点击“改变message”按钮后,含有v-once指令的变量,不改变值,说明未重新渲染;反之,没有v-once指令的,点击按钮后,值立刻发生变化,说明重新渲染了。

在这里插入图片描述


2.2_v-text指令

可用于更新元素的 textContent

<body>

  <div id="app">
    <h2> aa {
   
   {message}} bbb</h2>
    <h2 v-text="message">aabb</h2>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data: function() {
      
      
        return {
      
      
          message: "Hello Vue"
        }
      },
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

如下图所示,上半部分。未加v-text指令,所有文本可以正常显示;

加了v-text指令,会直接替换掉标签的文本内容。

在这里插入图片描述


2.3_v-html

默认情况下,如果展示的内容本身是 html 的,那么vue并不会对其进行特殊的解析。 如果希望这个内容被Vue可以解析出来,那么可以使用 v-html 来展示;

<body>

  <div id="app">
    <h2>{
   
   { content }}</h2>
    <h2 v-html="content"></h2>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data: function() {
      
      
        return {
      
      
          content: `<span style="color: red; font-size: 30px;">哈哈哈</span>`
        }
      },
    })
    // 2.挂载app
    app.mount("#app")
  </script>
</body>

如图,按正确格式加入v-html后,vue才能正确解析html文本

在这里插入图片描述


2.4_v-pre

用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签, 跳过不需要编译的节点,加快编译的速度

<body>

  <div id="app">
    <div v-pre>
      <h2>{
   
   { message }}</h2>
      <p>当前计数: {
   
   { counter }}</p>
      <p>{
   
   {}}</p>
    </div>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data: function() {
      
      
        return {
      
      
          message: "Hello Vue",
          counter: 0
        }
      },
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

如下图所示,使用了v-pre指令后,没有识别出{ {}},以及变量
在这里插入图片描述


2.5_v-cloak

保持在元素上直到关联组件实例结束编译。 和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到组件实例准备完毕。

<body>

  <div id="app">
    <h2 v-cloak>{
   
   {message}}</h2>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    setTimeout(() => {
      
      
      // 1.创建app
      const app = Vue.createApp({
      
      
        // data: option api
        data: function() {
      
      
          return {
      
      
            message: "Hello Vue"
          }
        },
      })
      // 2.挂载app
      app.mount("#app")
    }, 3000)

  </script>
</body>

按照如上代码运行,3s后,浏览器页面才显示组件及内容


2.6_v-memo

主要用来做性能优化。

缓存一个模板的子树。在元素和组件上都可以使用。为了实现缓存,该指令需要传入一个固定长度的依赖值数组进行比较。如果数组里的每个值都与最后一次的渲染相同,那么整个子树的更新将被跳过

<div v-memo="[valueA, valueB]">
  ...
</div>

当组件重新渲染,如果 valueAvalueB 都保持不变,这个 <div> 及其子项的所有更新都将被跳过。实际上,甚至虚拟 DOM 的 vnode 创建也将被跳过,因为缓存的子树副本可以被重新使用。

正确指定缓存数组很重要,否则应该生效的更新可能被跳过。v-memo 传入空依赖数组 (v-memo="[]") 将与 v-once 效果相同


3_v-bind绑定属性

3.1_v-bind的绑定属性

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

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

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

绑定属性使用v-bind:

  • 缩写::
  • 预期:any (with argument) | Object (without argument)
  • 参数:attrOrProp (optional)
  • 修饰符: .camel - 将 kebab-case attribute 名转换为 camelCase。
  • 用法:动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。
<body>

  <div id="app">
    <div>
      <button @click="switchImage">切换图片</button>
    </div>

    <!-- 1.绑定img的src属性 -->
    <img v-bind:src="showImgUrl" alt="">
    <!-- 语法糖: v-bind可以直接省略,只写冒号 : -->
    <img :src="showImgUrl" alt="">

    <!-- 2.绑定a的href属性 -->
    <a :href="href">百度一下</a>

  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data: function() {
      
      
        return {
      
      
          imgUrl1: "http://p1.music.126.net/agGc1qkogHtJQzjjyS-kAA==/109951167643767467.jpg",
          imgUrl2: "http://p1.music.126.net/_Q2zGH5wNR9xmY1aY7VmUw==/109951167643791745.jpg",
          showImgUrl: "http://p1.music.126.net/_Q2zGH5wNR9xmY1aY7VmUw==/109951167643791745.jpg",
          href: "http://www.baidu.com"
        }
      },
      methods: {
      
      
        switchImage: function() {
      
      
          this.showImgUrl = this.showImgUrl === this.imgUrl1 ? this.imgUrl2: this.imgUrl1
        }
      }
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

3.2_绑定class

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

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

绑定class有两种语法:

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

<body>

  <div id="app">
    <!-- 1.基本绑定class -->
    <h2 :class="classes">Hello World</h2>

    <!-- 2.动态class可以写对象语法 -->
    <button :class=" isActive ? 'active': '' " @click="btnClick">我是按钮1</button>

    <!-- 2.1.对象语法的基本使用(掌握)  isActive为true时,active留下,否则去除active-->
    <button :class="{ active: isActive }" @click="btnClick">我是按钮2</button>

    <!-- 2.2.对象语法的多个键值对 -->
    <button :class="{ active: isActive, hhh: true, kobe: false }" @click="btnClick">我是按钮3</button>
    
    <!-- 2.3.动态绑定的class是可以和普通的class同时的使用 -->
    <button class="abc cba" :class="{ active: isActive, hhh: true, kobe: false }" @click="btnClick">我是按钮</button>
    
    <!-- 2.4.动态绑定的class是可以和普通的class同时的使用 -->
    <button class="abc cba" :class="getDynamicClasses()" @click="btnClick">我是按钮4</button>
    
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data: function() {
      
      
        return {
      
      
          classes: "abc cba nba",
          isActive: false,
        }
      },

      methods: {
      
      
        btnClick: function() {
      
      
          this.isActive = !this.isActive
        },
        getDynamicClasses: function() {
      
      
          return {
      
       active: this.isActive, hhh: true, kobe: false }
        }
      }
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>    

(2)数组语法 :以把一个数组传给 :class,以应用一个 class 列表;

   <body>
  <div id="app">
    <!-- 3.动态class可以写数组语法(了解) -->
    <h2 :class="['abc', 'cba']">Hello Array</h2>
    <h2 :class="['abc', className]">Hello Array</h2>
    <h2 :class="['abc', className, isActive? 'active': '']">Hello Array</h2>
    <h2 :class="['abc', className, { active: isActive }]">Hello Array</h2>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data: function() {
      
      
        return {
      
      
          classes: "abc cba nba",
          isActive: false,
          className: "hhh"
        }
      }
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

3.3_绑定style

用v-bind:style来绑定一些CSS内联样式:

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

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

绑定class有两种方式:

  • 对象语法
  • 数组语法

demo:

<body>

  <div id="app">
    <!-- 1.普通的html写法 -->
      
    <h2 style="color: red; font-size: 30px;">哈哈哈哈</h2>
    <!-- 2.style中的某些值, 来自data中 -->
    <!-- 2.1.动态绑定style, 在后面跟上 对象类型 (重要)-->
    <h2 v-bind:style="{ color: fontColor, fontSize: fontSize + 'px' }">哈哈哈哈</h2>
    <!-- 2.2.动态的绑定属性, 这个属性是一个对象 -->
    <h2 :style="objStyle">呵呵呵呵</h2>
      
    <!-- 3.style的数组语法 ,数组中的每个元素,都是一个对象-->
    <h2 :style="[objStyle, { backgroundColor: 'purple' }]">嘿嘿嘿嘿</h2>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data: function() {
      
      
        return {
      
      
          fontColor: "blue",
          fontSize: 30,
          objStyle: {
      
      
            fontSize: '50px',
            color: "green"
          }
        }
      },
    })
    // 2.挂载app
    app.mount("#app")
  </script>
</body>

3.4_动态绑定属性

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

  • 前端无论绑定src、href、class、style,属性名称都是固定的;
  • 如果属性名称不是固定的,可以使用 : [属性名]=“值” 的格式来定义;
  • 这种绑定的方式,称之为动态绑定属性
<body>

  <div id="app">
    <h2 :[name]="'aaaa'">Hello World</h2>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data: function() {
      
      
        return {
      
      
          name: "class"
        }
      },
    })
    // 2.挂载app
    app.mount("#app")
  </script>
</body>

3.5_绑定一个对象

希望将一个对象的所有属性,绑定到元素上的所有属性,可以直接使用 v-bind 绑定一个 对象;

demo:info对象会被拆解成div的各个属性

<body>

  <div id="app">
    <h2 :name="name" :age="age" :height="height">Hello World</h2>

    <!-- v-bind绑定对象: 给组件传递参数 -->
    <h2 v-bind="infos">Hello Bind</h2>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data: function() {
      
      
        return {
      
      
          infos: {
      
       name: "hhh", age: 18, height: 1.88, address: "北京市" },

          name: "hhh",
          age: 18,
          height: 1.88
        }
      },
    })
    // 2.挂载app
    app.mount("#app")
  </script>
</body>

4_v-on绑定事件

前面的知识点,叙述了绑定元素的内容和属性,在前端开发中需要经常和用户进行各种各样的交互, 这个时候,就必须监听用户发生的事件,比如点击、拖拽、键盘事件等等。 在Vue中,使用v-on指令监听事件

4.1_v-on的基本使用

  • 监听点击事件

  • v-on:click可以写成@click,语法糖写法

  • 也可以绑定其他的事件,比如mouseover、mouseMove……等

  • 如果希望一个元素绑定多个事件,可以传入一个对象,对象里面的属性是键值对

<body>

  <div id="app">
    <!-- 1.完整的写法 -->
    <div class="box" v-on:click="divClick"></div>

    <!-- 2.语法糖写法(重点掌握) -->
    <div class="box" @click="divClick"></div>

    <!-- 3.绑定的方法位置, 也可以写成一个表达式(不常用, 不推荐) -->
    <h2>{
   
   { counter }}</h2>
    <button @click="counter--">-1</button>
    <button @click="counter++">+1</button>

    <!-- 4.绑定其他方法(掌握) 鼠标移动、窗口大小改变等 -->
    <div class="box" @mousemove="divMousemove"></div>

    <!-- 5.元素绑定多个事件(掌握) -->
        <!-- 第一种写法-->
    <div class="box" @click="divClick" @mousemove="divMousemove"></div>
        <!-- 第二种写法-->
    <!-- <div class="box" v-on="{ click: divClick, mousemove: divMousemove }"></div> -->
        <!-- 第三种写法-->
    <!-- <div class="box" @="{ click: divClick, mousemove: divMousemove }"></div> -->
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data: function() {
      
      
        return {
      
      
          counter: 0
        }
      },
      methods: {
      
      
        divClick() {
      
      
          console.log("divClick")
        },
        increment() {
      
      
          this.counter++
        },
        divMousemove() {
      
      
          console.log("divMousemove")
        }
      }
    })
    // 2.挂载app
    app.mount("#app")
  </script>
</body>

4.2_v-on参数传递

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

  • 情况一:如果该方法不需要额外参数,那么方法后的()可以不添加。 但是注意:如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去
  • 情况二:如果只传递 自己设定的参数,直接写进() 中
  • 情况三:如果需要同时传入设定的参数,以及默认的event时,默认event必须写成$event传入事件。
<body>

  <div id="app">
    <!-- 1.默认传递event对象 -->
    <button @click="btn1Click">按钮1</button>
    <!-- 2.传递自己的参数 -->
    <button @click="btn2Click('hhh', age)">按钮2</button>
    <!-- 3.传递自己的参数+默认event对象 -->
    <!-- 必须在模板中明确获取event对象: $event -->
    <button @click="btn3Click('hhh', age, $event)">按钮3</button>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      data: function() {
      
      
        return {
      
      
          message: "Hello Vue",
          age: 18
        }
      },
      methods: {
      
      
        // 1.默认参数: event对象
        // 总结: 如果在绑定事件的时候, 没有传递任何的参数, 那么event对象会被默认传递进来
        btn1Click() {
      
      
          console.log("btn1Click:", event)
        },
        // 2.自己的参数:
        btn2Click(name, age) {
      
      
          console.log("btn2Click:", name, age)
        },
        // 3.自己的参数+event对象
        btn3Click(name, age, event) {
      
      
          console.log("btn3Click:", name, age, event)
        }
      }
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

4.3_v-on的修饰符(了解)

修饰符相当于对事件进行了一些特殊的处理:

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

5_Vue的条件渲染

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

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

  • v-if
  • v-else
  • v-else-if
  • v-show

5.1_v-if、v-else、v-else-if

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

  • 这些内容只有在条件为true时,才会被渲染出来;
  • 这三个指令与JavaScript的条件语句if、else、else if类似;

v-if的渲染原理:

  • v-if是惰性的;
  • 当条件为false时,其判断的内容完全不会被渲染或者会被销毁掉;
  • 当条件为true时,才会真正渲染条件块中的内容;

v-if 、v-else演示

<body>

  <div id="app">
    <!-- v-if="条件" -->
    <div class="info" v-if="Object.keys(info).length">
      <h2>个人信息</h2>
      <ul>
        <li>姓名: {
   
   {info.name}}</li>
        <li>年龄: {
   
   {info.age}}</li>
      </ul>
    </div>

    <!-- v-else -->
    <div v-else>
      <h2>没有输入个人信息</h2>
      <p>请输入个人信息后, 再进行展示~</p>
    </div>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data() {
      
      
        return {
      
      
          info: {
      
      }
        }
      }
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

效果如下图

在这里插入图片描述


v-if v-else-if v-else演示

<body>

  <div id="app">
    <h1 v-if="score > 90">优秀</h1>
    <h2 v-else-if="score > 80">良好</h2>
    <h3 v-else-if="score >= 60">及格</h3>
    <h4 v-else>不及格</h4>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data() {
      
      
        return {
      
      
          score: 40
        }
      },
    })
    // 2.挂载app
    app.mount("#app")
  </script>
</body>

5.2_template元素

像5.1的代码,v-if/else-if指令放在div中,导致渲染出来的元素,也包含div。但是v-if/else-if指令又必须放在元素中。

如果希望渲染出来的元素没有div包裹,又必须含有v-if/else-if指令,可以用template元素替代div。

template元素可当做不可见的包裹元素,并且在v-if上使用,但是最终template不会被渲染出来, 有点类似于小程序中的block。

下面的代码在5.1 v-else的基础上,修改了div

  <div id="app">
    <!-- v-if="条件" -->
    <template v-if="Object.keys(info).length">
      <h2>个人信息</h2>
      <ul>
        <li>姓名: {
   
   {info.name}}</li>
        <li>年龄: {
   
   {info.age}}</li>
      </ul>
    </template>

    <!-- v-else -->
    <template v-else>
      <h2>没有输入个人信息</h2>
      <p>请输入个人信息后, 再进行展示~</p>
    </template>
  </div>

下图所示效果

在这里插入图片描述


5.3_v-show

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

5.2的代码用v-show替换

  <div id="app">
    <!-- v-if="条件" -->
    <div  v-show="Object.keys(info).length > 0">
      <h2>个人信息</h2>
      <ul>
        <li>姓名: {
   
   {info.name}}</li>
        <li>年龄: {
   
   {info.age}}</li>
      </ul>
    </div>

    <!-- v-else -->
    <div  v-show="Object.keys(info).length <= 0">
      <h2>没有输入个人信息</h2>
      <p>请输入个人信息后, 再进行展示~</p>
    </div>
  </div>

但是v-show与v-if是有区别的

(1) 用法上的区别:

  • v-show是不支持template;
  • v-show不可以和v-else一起使用;

(2)本质的区别:Object.keys(info).length

  • v-show元素无论是否需要显示到浏览器上,它的DOM实际都是有存在的,只是通过CSS的display属性来进行切换;
  • v-if当条件为false时,其对应的原生压根不会被渲染到DOM中;

(3) 开发选择?

  • 如果需求是在显示和隐藏之间频繁的切换,那么使用v-show;减少重绘与回流
  • 如果不会频繁的发生切换,那么使用v-if;
  • 如果实际效果,使用div更好,则优先使用div。
  • 如果div作用不大,优先使用template

6_v-for

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

  • 这个时候可以使用v-for来完成;
  • v-for类似于JavaScript的for循环,可以用于遍历一组数据;

6.1_v-for基本使用

v-for的基本格式是==“item in 数组”==:

  • 数组通常是来自data或者prop,也可以是其他方式;
  • item是给每项元素起的一个别名,这个别名可以自定来定义;

在遍历一个数组的时,经常需要拿到数组的索引:

  • 如果需要索引,可以使用格式: “(item, index) in 数组”
  • 注意顺序:数组元素项item是在前面的,索引项index是在后面的;
<body>

  <div id="app">
    <!-- 1.电影列表进行渲染 -->
    <h2>电影列表</h2>
    <ul>
      <li v-for="movie in movies">{
   
   { movie }}</li>
    </ul>

    <!-- 2.电影列表同时有索引 -->
    <ul>
      <li v-for="(movie, index) in movies">{
   
   {index + 1}} - {
   
   { movie }}</li>
    </ul>

    <!-- 3.遍历数组复杂数据 -->
    <h2>商品列表</h2>
    <div class="item" v-for="item in products">
      <h3 class="title">商品: {
   
   {item.name}}</h3>
      <span>价格: {
   
   {item.price}}</span>
      <p>秒杀: {
   
   {item.desc}}</p>
    </div>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data() {
      
      
        return {
      
      
          // 1.movies
          movies: ["星际穿越", "少年派", "大话西游", "哆啦A梦"],
          // 2.数组: 存放的是对象
          products: [
            {
      
       id: 110, name: "Macbook", price: 9.9, desc: "9.9秒杀, 快来抢购!" },
            {
      
       id: 111, name: "iPhone", price: 8.8, desc: "9.9秒杀, 快来抢购!" },
            {
      
       id: 112, name: "小米电脑", price: 9.9, desc: "9.9秒杀, 快来抢购!" },
          ]
        }
      },
    })
    // 2.挂载app
    app.mount("#app")
  </script>
</body>

6.2_v-for支持的类型

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

  • 一个参数: “value in object”;
  • 二个参数: “(value, key) in object”;
  • 三个参数: “(value, key, index) in object”;

v-for同时也支持数字的遍历, 每一个item都是一个数字;

v-for也可以遍历其他可迭代对象(Iterable)

<body>

  <div id="app">
    <!-- 1.遍历数组 略 -->

    <!-- 2.遍历对象 ,如下所示 -->
    <ul>
      <li v-for="(value, key, index) in info">{
   
   {value}}-{
   
   {key}}-{
   
   {index}}</li>
    </ul>

    <!-- 3.遍历字符串(iterable) -->
    <ul>
      <li v-for="item in message">{
   
   {item}}</li>
    </ul>

    <!-- 4.遍历数字 -->
    <ul>
      <li v-for="item in 5">{
   
   {item}}</li>
    </ul>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data() {
      
      
        return {
      
      
          message: "Hello Vue",
          movies: [],
          info: {
      
       name: "hhh", age: 18, height: 1.88 }
        }
      },
    })
    // 2.挂载app
    app.mount("#app")
  </script>
</body>

效果如下所示

在这里插入图片描述


6.3_数组更新检测

Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。

这些被包裹过的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

替换数组的方法

  • 上面的方法会直接修改原来的数组;
  • 但是某些方法不会替换原来的数组,而是会生成新的数组,比如 filter()、concat() 和 slice();那么这样的数组就不会触发视图更新

6.4_v-for中的key

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

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

  • key属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes;
  • 如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法;
  • 而使用key时,它会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素;

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

  • 什么是新旧nodes,什么是VNode?
  • 没有key的时候,如何尝试修改和复用的?
  • 有key的时候,如何基于key重新排列的

7_虚拟DOM

7.1_认识VNod

  • 目前先理解HTML元素创建出来的VNode;
  • VNode的全称是Virtual Node,也就是虚拟节点;
  • 事实上,无论是组件还是元素,它们最终在Vue中表示出来的都是一个个VNode;
  • VNode的本质是一个JavaScript的对象;

在这里插入图片描述

如果不是一个简单的div,而是有一大堆的元素,那么会形成一个VNode Tree。

在这里插入图片描述


7.2_插入元素的案例

是当点击按钮时会在中间插入一个f;

<body>

  <div id="app">
    <button @click="insertF">插入f</button>
    <ul>
      <!-- key要求是唯一: id -->
      <li v-for="item in letters" :key="item">{
   
   {item}}</li>
    </ul>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      
      
      // data: option api
      data() {
      
      
        return {
      
      
          letters: ["a", "b", "c", "d", "e"]
        }
      },
      methods: {
      
      
        insertF() {
      
      
          this.letters.splice(2, 0, "f")

          this.letters.splice()
        }
      }
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

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

  • 在Vue中,对于相同父元素的子元素节点并不会重新渲染整个列
    表;
  • 因为对于列表中 a、b、c、d它们都是没有变化的;
  • 在操作真实DOM的时候,只需要在中间插入一个f的li即可;

Vue中对于列表更新的操作过程?

  • Vue会对于有key和没有key会调用两个不同的方法;
  • 有key,那么就使用 patchKeyedChildren方法;
  • 没有key,就使用 patchUnkeyedChildren方法;

7.3_v-for没有key

如下图所示,收到新增 f 命令后,c 、d的li元素不变,但是内容上要改变。故原来的c元素 被 f 使用,后续所有的内容都要进行一次改动,并且最后进行新增;

在这里插入图片描述


7.4_v-for有key的diff算法

第一步的操作是从头开始进行遍历、比较:
a和b是一致的会继续进行比较;
c和f因为key不一致,所以就会break跳出循环;

在这里插入图片描述

第二步的操作是从尾部开始进行遍历、比较,如图所示

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

所以可以发现,Vue在进行diff算法的时候,会尽量利用的key来进行优化操作:
在没有key的时候的效率是非常低效的;在进行插入或者重置顺序的时候,保持相同的key可以让diff算法更加的高效;

},
methods: {
insertF() {
this.letters.splice(2, 0, “f”)

      this.letters.splice()
    }
  }
})

// 2.挂载app
app.mount("#app")
```

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

  • 在Vue中,对于相同父元素的子元素节点并不会重新渲染整个列
    表;
  • 因为对于列表中 a、b、c、d它们都是没有变化的;
  • 在操作真实DOM的时候,只需要在中间插入一个f的li即可;

Vue中对于列表更新的操作过程?

  • Vue会对于有key和没有key会调用两个不同的方法;
  • 有key,那么就使用 patchKeyedChildren方法;
  • 没有key,就使用 patchUnkeyedChildren方法;

猜你喜欢

转载自blog.csdn.net/qq_54075517/article/details/132148197