第二节:模板语法

171 阅读7分钟

附:「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战

1. 模板语法

1.1 什么是模板语法?

Vue中在 template 里写HTML,这个就是模板语法。示例代码如下:

<template>
 <div :class="active ? active : '' ">Hello World</div>  
</template>

1.2 开发模式:React VS Vue

(1)React

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

(2)Vue

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

1.3 Mustche双大括号语法

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

(1)正确的用法:

<!-- 1. Mustache的基本使用 -->
<div>{{ message }}</div>    

<!-- 2. 里面可以写表达式 -->
<div>{{ count * 10}}</div>
<div>{{ message.split(" ").reverse().join(" ") }}</div>

<!-- 3. 支持三元运算符 -->
<div>{{ isShow ? '哈哈哈' : ''}}</div>
<button @click="toggle">切换</button>

<!-- 4. 也可以用计算属性 -->
<div>{{ getReverseMessage }}</div>

(2)错误用法

 <!-- 1. 不能写赋值语句 -->
<div>{{ var name = "abc"}}</div>

<!-- 2. 不能写if语句 -->
<div>{{ if(isShow) return "哈哈哈"}}</div>

2. 基本指令

2.1 v-once

  • 该指令用于指定元素或者组件只渲染一次。当数据发生变化时,元素或者组件以及其所有的子元素将视为静态内容并且跳过。
  • 该指令可以用于性能优化。
<div>当前计数:{{ count }}</div>
<div v-once>当前计数:{{ count }}</div>
<button @click="add">+1</button>

2.2 v-text

该指令用于更新元素的文本内容

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

<!-- 上面代码相当于 <div>{{message}}</div>  -->

输出结果:

2.3 v-html

  • 默认情况下,如果要展示的内容本身是 html 的,那么vue并不会对其进行特殊的解析。
  • 如果我们希望这个内容被Vue可以解析出来,那么可以使用 v-html 来展示。
<body>
  
  <div id="app"></div>

  <template id="my-app">
     <div v-html="info"></div>
  </template>

  <script src="js/vue.js"></script>
  <script>
    const App = {
      template: '#my-app',
      data() {
        return {
          info: `<span style="color: red; font-size: 22px">哈哈哈</span>`
        }
      },
      methods: {}
    }

    Vue.createApp(App).mount('#app');
  </script>
</body>

输出结果:

2.4 v-pre

  • 该指令用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签。跳过不需要编译的节点,加快编译的速度。
<template id="my-app">
   <div v-pre>这个是添加v-pre的:{{ message }}</div>
   <div>这个是没有添加v-pre的:{{ message }}</div>
</template>

输出结果:

2.5 v-bind 绑定属性、class、style

  • 该指令用于给属性动态绑定。比如动态绑定a元素的href属性或者是动态绑定img元素的src属性。
  • v-bind可以绑定一个或多个属性值,或者向另一个组件传递props值。
  • v-bind的语法糖写法是:
<!-- 1. v-bind的基本使用 -->
<img v-bind:src="imgUrl">
<a v-bind:href="link" target="_blank">百度一下</a>

<!-- 2. v-bind的语法糖 -->
<img :src="imgUrl">
<a :href="link" target="_blank">百度一下</a>

输出结果:

2.5.1 绑定class

在开发中,有时候我们的元素class也是动态的,比如:当数据为某个状态时,字体显示红色。当数据另一个状态时,字体显示黑色。class一般都是键值对的写法,如果值为true就加class,反则不加

绑定class有两种方式:对象语法、数组语法

(1)对象语法

<template id="my-app">
    <!-- 1. 普通的绑定方式 -->
    <div :class="className">{{ message }}</div>

    <!-- 2. 对象绑定 -->
    <!-- 动态添加类名,value为true会给当前元素添加类名,false则不添加 -->
    <div class="xiaohe1" :class="{xiaohe2:false,xiaohe3: true}">{{ message }}</div>

    <!-- 3. 绑定对象 -->
    <div :class="classObj">{{ message }}</div>

    <!-- 4. 从methods中获取添加 -->
    <div :class="classObj2()">{{ message }}</div>
</template>

<script>
  export default {
   data(){
    return {
       message: "Hello World",
          className: 'xiaohe',
          classObj:{
            xiaohe1: true,
            xiaohe2: true,
            xiaohe3: false
       }
    }
   },
    methods: {
        classObj2(){
          return {
            xiaohe4: true,
            xiaohe5: true
          }
        }
      }
  }
</script>

(2)数组语法

<body>
   
    <div id="app"></div>

    <template id="my-app">
      <div :class="['abc1', title]">哈哈哈哈</div>
      <div :class="['abc1', title, isActive ? 'active': '']">哈哈哈哈</div>
      <div :class="['abc1', title, {active: isActive}]">哈哈哈哈</div>
    </template>
  
    <script src="../js/vue.js"></script>
    <script>
      const App = {
        template: '#my-app',
        data() {
          return {
            message: "Hello World",
            title: "abc2",
            isActive: true
          }
        }
      }
  
      Vue.createApp(App).mount('#app');
    </script>
</body>

(3)注意事项

  1. key和value可以不用加引号,如:container:true
  2. 默认class和动态class可以结合使用
2.5.2 绑定style

我们可以利用 v-bind:style 来绑定一些CSS内联样式,比如某段文字的颜色、大小等

绑定style有两种方式:对象语法、数组语法

(1)对象语法

<body>
  
  <div id="app"></div>

  <template id="my-app">
    <!-- 1. 基本使用 -->
    <div :style="{color: 'red' , fontSize: '30px' }">{{message}}</div>
 
    <!-- 2. 对象数据 -->
    <div :style="styleObj">{{ message }}</div>

    <!-- 3. 调用一个方法 -->
    <div :style="styleObj2()">{{ message }}</div>

</template>

  <script src="js/vue.js"></script>
  <script>
    const App = {
      template: '#my-app',
      data() {
        return {
          message: "Hello World",
          styleObj:{
              'font-size': '30px',
              'color': 'red',
              'background-color': 'skyblue'
          }
        }
      },
      methods: {
        styleObj2(){
            return {
              'font-size': '30px',
              'color': 'red',
              'background-color': 'green'
            }
        }
      }
    }

    Vue.createApp(App).mount('#app');
  </script>
</body>

输出结果:

(2)数组语法

<body>
  
  <div id="app"></div>

  <template id="my-app">
    <div :style="[styleObj1]">{{message}}</div>
  </template>

  <script src="js/vue.js"></script>
  <script>
    const App = {
      template: '#my-app',
      data() {
        return {
          message: "Hello World",
          styleObj1:{
              'font-size': '30px',
              'color': 'red',
              'background-color': 'green'
          }
        }
      },
    }

    Vue.createApp(App).mount('#app');
  </script>
</body>

输出结果:

(3)注意事项

  1. key可以不用加引号,但是value一定要加。如:font-size: "24px"。与绑定style不一样,要注意一下
  2. font-size 这样多一个 - 的写法,绑定style是不认识的这种写法的,会报错。如果一定要使用,可以用引号圈起来,如:'font-size' 或者使用驼峰语法 fontSize ,
2.5.3 动态绑定属性

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

  • 前端我们无论绑定src、href、class、style,属性名称都是固定的
  • 如果属性名称不是固定的,我们可以使用 :[属性名] = "值" 的格式来定义
  • 这种绑定的方式,我们称之为动态绑定属性
<template id="my-app">
  <!-- 1. 绑定单个属性名称 -->
  <div :[name]="value">{{message}}</div>

  <!-- 2. 绑定一个对象的属性名称 -->
  <div v-bind="info">{{message}}</div>
</template>

<script>
    const App = {
      template: '#my-app',
      data() {
        return {
          message: "Hello World",
          name: 'name1',
          value: 'xiaohe',
          info: {
              name: 'xiaohe',
              age: 18,
              hobby: 'run'
          }
        }
      },
    }
</script>

输出结果:

2.6 v-on 绑定事件

  • 该指令用于监听用户发生的事件,比如点击、拖拽、键盘事件等等
2.6.1 基本使用
<template id="my-app">
      <div>{{ count }}</div>
      <!-- 1. 绑定一个表达式 -->
      <button @click="btnClick1">按钮1</button>

      <!-- 2. 绑定到一个 methods 方法中 -->
      <button @click="btnClick2">按钮2</button>
    
      <!-- 3. 绑定鼠标移动事件 -->
      <div class="box" @mousemove="mouseMove">mousemove</div>

      <!-- 4. 绑定多个事件 -->
      <!-- 事件名: 事件处理函数-->
      <div v-on="{click:btnClick3, mousemove: mouseMove2}" class="box2">click、mousemove</div>

</template>

<script>
    const App = {
      template: '#my-app',
      data() {
        return {
          count: 0
        }
      },
      methods: {
        btnClick1(){
            this.count++
        },
        btnClick2(){
            this.count++
        },
        mouseMove(){
            console.log('鼠标移动了');
        },
        btnClick3(){
            this.count++
        }
      }
    }
</script>
2.6.2 参数传递
<template id="my-app">
    <div>{{ count }}</div>
    <!-- 1. 默认会把 event 对象传入 -->
    <button @click="btnClick">+1</button>

    <!-- 2. 传入其他参数 -->
    <!-- 如果需要传递其他参数,需要使用$event-->
    <button @click="btnClick2($event, 'xiaohe')">+1</button>
</template>

<script>
    const App = {
      template: '#my-app',
      data() {
        return {
          count: 0
        }
      },
      methods: {
        btnClick(event){
            console.log(event);  
        },
        btnClick2(event,name){
            console.log(event,name);  
        }
      },
    }
</script>

注意事项:

  1. 如果该方法不需要额外参数,那么方法后的()可以不添加。但是要注意,如果方法本身中有一个参数,那么会默认将原生事件 event 参数传递进去。
  2. 如果需要同时传入某个参数,同时需要 event 时,可以通过$event传入事件。
2.6.3 修饰符

v-on支持修饰符,修饰符相当于对事件进行了一些特殊的处理,示例代码如下:

<template id="my-app">
        <!-- 修饰符 -->
        <!-- 1. 默认当我们点击按钮的时候,事件处理函数会冒泡到 divClick,当我们在按钮上加了.stop,就会阻止冒泡了 -->
        <div @click="divClick">
            <button @click.stop="btnClick">按钮</button>
        </div>

        <!-- 2. 回车后才触发 -->
        <input type="text" @keyup.enter="onEnter">
</template>

    <script src="js/vue.js"></script>
    <script>
        const App = {
            template: '#my-app',
            data() {
                return {
                    message: "Hello World",
                }
            },
            methods: {
                divClick() {
                    console.log('divClick');
                },
                btnClick() {
                    console.log('btnClick');
                },
                onEnter(event) {
                    console.log(event.target.value);
                }
            }
        }
    </script>

参考文章:juejin.cn/search?quer…

3. 条件渲染

3.1 v-if、v-else-if、v-else

该指令用于根据条件来渲染某一块的内容,这些内容只有在条件为 true 时,才会被渲染出来。示例代码如下:

3.1.1 单个内容使用(v-if)
<template id="my-app">
  <div v-if="isShow">{{ message }}</div>
  <button @click="toggle">切换</button>
</template>

<script>
    const App = {
      template: '#my-app',
      data() {
        return {
          message: "Hello World",
          isShow: true
        }
      },
      methods: {
         toggle(){
             this.isShow = !this.isShow;
         }
      }
    }
</script>

输出结果:

3.1.2 多个内容使用(v-if、v-else-if、v-else)

这里我用了 template 做包裹来判断,减少了DOM的操作。

<template id="my-app">
    <template v-if="isShow">
       <div>哈哈哈</div>
       <div>哈哈哈</div>
       <div>哈哈哈</div>
    </template>

    <template v-else>
        <div>呵呵呵</div>
        <div>呵呵呵</div>
        <div>呵呵呵</div>
    </template>

     <button @click="toggle">切换</button>
</template>

<script>
    const App = {
      template: '#my-app',
      data() {
        return {
            isShow: true
        }
      },
      methods: {
        toggle(){
            this.isShow = !this.isShow;
        }
      }
    }
  </script>
3.1.3 案例
<template id="my-app">
     <span>本次成绩:</span>
     <span v-if="scores > 90">优秀</span>
     <span v-else-if="scores > 60 ">良好</span>
     <span v-else>不及格</span>

     <div>
         <input type="text" v-model="scores">
     </div>
</template>

<script>
   const App = {
         template: '#my-app',
         data() {
            return {
              scores: 80
             }
          },
        }
</script>

输出结果:

3.2 v-show

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

<template id="my-app">
  <div v-show="isShow">{{ message }}</div>
</template>

<script>
  const App = {
     template: '#my-app',
     data() {
        return {
          message: "Hello World",
          isShow: true
        }
      }
    }
</script>

输出结果:

3.3 v-if和v-show的区别

(1)本质的区别

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

(2)开发时选择

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

4. 列表渲染

在真实开发中,我们往往会从服务器拿到一组数据,并且需要对其进行渲染。 这个时候我们可以使用 v-for 来完成; v-for类似于JavaScript的for循环,可以用于遍历一组数据;

4.1 v-for 基本使用

v-for的基本格式是 "item in 数组": 数组通常是来自data或者prop,也可以是其他方式; item是我们给每项元素起的一个别名,这个别名可以自定来定义;我们知道,在遍历一个数组的时候会经常需要拿到数组的索引: 如果我们需要索引,可以使用格式: "(item, index) in 数组";注意上面的顺序:数组元素项item是在前面的,索引项index是在后面的;

4.1.1 遍历数组

语法:(item,index) in 数组,第一个是item是数组的每一项,第二个index是数组每一项的索引。

<template id="my-app">
    <!-- 1. 每一项 -->
    <ul>
        <li v-for="movie in movies">{{ movie }}</li>
    </ul>

    <!-- 2. 每一项 + 索引 -->
    <ul>
        <li v-for="(movie,index) in movies">{{index}} ---- {{ movie }}</li>
    </ul>
</template>

<script>
    const App = {
      template: '#my-app',
      data() {
        return {
            movies: [
                '流浪地球',
                '功勋',
                '我和我的父辈',
                '战狼'
            ]
        }
      },
    }
</script>

输出结果:

4.1.2 遍历对象

语法:(value,key,index) in 对象

<template id="my-app">
   <ul>
      <li v-for="(value,key,index) in info">{{index}}-{{key}}-{{value}}</li>
   </ul>
</template>

<script>
    const App = {
      template: '#my-app',
      data() {
        return {
          info:{
              name: 'xiaohe',
              age: 18,
              hobby: 'run'
          }
        }
      },
    }
</script>

输出结果:

4.1.3 遍历数字

语法:(item,index)in 数字

<template id="my-app">
   <ul>
      <li v-for="(item,index) in 10">{{index}}--{{item}}</li>
   </ul>
</template>

<script>
    const App = {
      template: '#my-app',
      data() {
        return {}
      },
    }
</script>

输出结果:

5. template VS div

template元素是不会被渲染到浏览器上的,而 div 是会被渲染到浏览器上,很多情况下使用 v-if 和 v-for,如果需要一个占位应该优先考虑 template。

(1)第一种情况:v-if时,如果你用 div 会增加一次DOM操作,而使用 template则不会。

<template id="my-app">
    <template v-if="isShow">
       <div>哈哈哈</div>
       <div>哈哈哈</div>
       <div>哈哈哈</div>
    </template>

    <template v-else>
        <div>呵呵呵</div>
        <div>呵呵呵</div>
        <div>呵呵呵</div>
    </template>
</template>

(2)第二种情况:v-for时

<template id="my-app">
   <ul>
     <template v-for="(value,key) in info">
       <li>{{ key }}</li>
       <li>{{ value }}</li>
       <hr>
      </template>
   </ul>
</template>

注意:

  1. v-show 是不支持template的