Vue3学习 --- 模板语法

1,237 阅读6分钟

模板语法

在React使用的jsx,所以对应的代码都是编写的类似于将JS嵌入到HTML中的一种语法,之后需要通过Babel将jsx编译成 React.createElement 函数调用。

Vue也支持jsx的开发模式,但是大多数情况下,使用基于HTML的模板语法。

在模板中,允许开发者以声明式的方式将DOM和底层组件实例的数据绑定在一起(mustache语法在模板中绑定对应data)

在底层的实现中,Vue会将模板编译成虚拟DOM,随后使用render函数进行界面渲染

Mustache语法

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

data返回的对象是有添加到Vue的响应式系统中,因此当data中的数据发生改变时,对应的内容也会自动发生更新。

<!-- 1. 基本使用 -->
<h2>{{ msg }}</h2>

<!-- 2. 可以同时使用多个mustache -->
<h2>{{ msg }} --- {{ msg }}</h2>

<!-- 3. mustache中可以使用任何合法的js表达式 -->
<h2>{{ msg.toUpperCase() }}</h2>
<h2>{{ isLogin ? 'Login Out': 'Login In' }}</h2>

<!-- 4. 可以在mustache中调用函数和使用计算属性 -->
<h2>{{ reverseMsg }}</h2>
<h2>{{ getReverseMsg() }}</h2>

常见指令

v-once

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

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

该指令可以用于性能优化

<!-- count值不会发生改变 -->
<h2 v-once>{{ count }}</h2>

<!-- 元素及其子元素都不会再重新渲染 -->
<div v-once>
  <h2>{{ count }}</h2>
</div>
v-text
<h2>{{ msg }}</h2>

<!-- 等价于 -->
<h2 v-text="msg"></h2>
v-html

vue在解析模板的时候,会将data中的数据当做字符串进行解析

如果data中的数据是一段html标签的时候,vue依旧会将其作为字符串去进行渲染

如果需要vue将其作为html标签去渲染的时候,可以使用v-html

但是因为这段数据可能来自于第三方,所以为了避免XSS攻击,请确保这些数据的可靠性

<!--<h2>Hello World</h2> -->
<h2>{{ msg }}</h2>

<!-- Hello World -->
<h2 v-html="msg"></h2>
v-pre

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

v-pre可以跳过不需要编译的节点,加快编译的速度

<h2 v-pre>{{ msg }}</h2>
<h2>{{ msg }}</h2>
v-bind

V-bind ---> 可以动态绑定属性 ---> 动态地绑定一个或多个 attribute,或一个组件 prop 到表达式

<a v-bind:href="link">google</a>

<!-- 简写 ===> 语法糖 -->
<a :href="link">google</a>

使用v-bind绑定class

  1. 普通绑定

    <span :class="active">Hello World</span>
    
  2. 对象语法

    <!-- 对象语法: {样式: boolean值} boolean值为true的时候,会显示样式, 为false的时候,不显示样式 -->
    <h2 :class="{active: isActive}">Hello World</h2>
    
    <!-- 对象中的key可以是变量 -->
    <h2 :class="{[active]: isActive}">Hello World</h2>
    
    <!-- 也可以有多个键值对 -->
    <h2 :class="{active: isActive, foo: isFoo}">Hello World</h2>
    
    <!-- 默认的class和动态的class结合 -->
    <h2 class="foo" :class="{active: isActive}">Hello World</h2>
    
    <!-- 抽离为一个单独的对象 -->
    <h2 :class="classObj">Hello World</h2>
    
    <!-- 抽离为方法或计算属性 -->
    <h2 :class="getClassObj()">Hello World</h2>
    
  3. 数组语法

    <!-- 数组中可以是字符串,也可以是变量 -->
    <h2 :class="['foo', active]">Hello World</h2>
    
    <!-- 可以是三目运算符 -->
    <h2 :class="['foo', isActive ? 'active' : '']">Hello World</h2>
    
    <!-- 数组中某一项的返回值是boolean,无论是true还是false,这一项就不会在样式中显示 -->
    <h2 :class="['foo', isActive && 'active']">Hello World</h2>
    
    <!-- 数组中可以嵌套对象语法 -->
    <h2 :class="['foo', { 'active': isActive }]">Hello World</h2>
    

使用v-bind绑定style

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

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

  1. 对象语法

    <!-- 属性值要使用字符串包裹,不然会被作为变量去进行解析 -->
    <h2 :style="{color: 'red', backgroundColor: 'gray'}">Hello World</h2>
    
    <!-- 属性名可以使用驼峰或短划法,如果是短划线需要使用引号将属性名进行包裹 -->
    <h2 :style="{color: 'red', 'background-color': 'gray'}">Hello World</h2>
    
  2. 数组语法

    <!-- 对象数组中的每一项都是一个style对象,可以直接写,也可以抽离成一个对象来引用 -->
    <h2 :style="[{color: 'red'}, {backgroundColor: 'gray'}]">Hello World</h2>
    

动态绑定属性

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

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

<!--
    1. 属性名 要么是全小写,要么是中划线写法,因为html不区分大小写,所以在HTML模板中,属性名会被转换为全小写(propertyName -> propertyname)
    2. 属性名如果是key的时候,key会被vue作为特殊属性在元素更新的时候使用,所以最终不会被渲染在元素的属性上
    3. 使用动态绑定属性,就意味着属性名一定是变量,所以会使用v-bind
       此时如果值是字符串的时候,需要手动加上引号,避免值被作为变量进行解析
       如果不是有v-bind,此时vue会将[xxx]作为普通字符串属性名进行解析,而这不是一个合法的属性名
-->
<h2 :[name]="'propertyValue'">Hello World</h2>

绑定一个对象

如果我们希望将一个对象的所有属性,绑定到元素上的时候,可以直接绑定一个对象,vue在解析的时候会将对象展开后在进行传递,这对于传递props是十分有帮助的。

<!-- <h2 name="Klaus" age="23">Hello World</h2> -->
<h2 v-bind="userInfo">Hello World</h2>

<!-- 简写 --- 语法糖 -->
<h2 :="userInfo">Hello World</h2>
v-on

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

在Vue中如何监听事件 就需要使用v-on指令

<button v-on:click="handleClick">click me</button>

<!-- 简写 -->
<button @click="handleClick">click me</button>
<!-- v-on 的属性值可以是 function | inline statement | object -->

<!-- function -->
<button v-on:click="handleClick">click me</button>

<!-- inline statement -->
<button v-on:click="count++">{{ count }}</button>

<!-- object --- 用于同时绑定多个事件 -->
<button v-on="{ click: handleClick, mouseup: handleMouseUp }">click me</button>

参数传递

<!-- 如果函数没有任何的参数,那么vue会默认给事件处理函数一个参数,即事件对象event -->
<button v-on:click="handleClick">click me</button>

methods: {
  handleClick(e) {
    console.log(e)
  }
}
<!--
  如果函数传递了参数,此时如果需要再获取事件参数对象的时候,需要自己手动传入$event
  $event 是vue封装好的特殊变量,表示的就是对应事件的事件对象
-->
<button v-on:click="handleClick('msg', $event)">click me</button>

methods: {
    handleClick(msg, e) {
      console.log(e, msg)
    }
}

事件修饰符

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

修饰符作用备注
.stop调用 event.stopPropagation()
.prevent调用 event.preventDefault()
.capture添加事件侦听器时使用 capture 模式
.self只当事件是从侦听器绑定的元素本身触发时才触发回
.{keyAlias}仅当事件是从特定键触发时才触发回调keyAlias表示的是按键别名,
如enter,delete, tab, space ... 等
.once只触发一次回调
.left只当点击鼠标左键时触发
.right只当点击鼠标右键时触发
.middle只当点击鼠标中键时触发
.passive{ passive: true } 模式添加侦听器表示在进行事件处理的时候,显示的告诉浏览器,
不会阻止默认事件,即不需要去检测是否有阻止默认行为
这对于一些会频繁调用多次的事件(如scroll, mousemove等)会有性能提升的效果
<div @click="handleDIVClick">
  <button @click.stop="handleBtnClick">click me</button>
</div>

字符串模板和DOM模板

字符串模板

字符串模板就是写在vue中的template中定义的模板

  • vue的单文件组件模板
  • 定义组件时template属性值的模板(没有被抽取出去的时候)

字符串模板不会在页面初始化参与页面的渲染,会被vue进行解析编译之后再被浏览器渲染,所以不受限于html不区分大小写的影响。

Vue.component('Cpn', {
   // MyComponent 定义在template中,会先经过vue的解析再渲染,所以其命名不受限于html不区分大小写的影响
   template: '<div MyId="123"><MyComponent>hello, world</MyComponent></div>'
})

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

dom模板

dom模板(又被称为Html模板)

dom模板就是写在html文件中,一打开就会被浏览器进行解析渲染的,即在经过vue解析之前就会先被浏览器所解析

因为html不区分大小写,所以此时类似于myComponent会被浏览器转换为mycomponent,此时在交给vue去进行解析的时候就会出现问题

<html>
  <head>
    <meta charset="utf-8">
    <title>Vue Component</title>
  </head>
  <body>
    <div id="app"> 
      Hello Vue
      <MyComponent></MyComponent>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <script >
      // MyComponent被解析为了mycomponent,所以vue找不到MyComponent这个组件,会报错
      Vue.component('MyComponent', {
        template: '<div>组件内容</div>'
      });
      new Vue ({
        el: '#app'
      });
    </script>
  </body>
</html>

因此vue推荐在使用组件的时候,使用中划线的方式去使用(如my-component),而不是使用驼峰法(如MyComponent)的方式去使用。

扩展

在html中有一些属性比较特别,它就是驼峰定义的(例如svg标签中的viewBox属性),所以以驼峰方式使用的时候不会有任何的问题

<svg style="width:150px; height:300px" viewBox="0 0 400 400">
  <circle cx="200" cy="200" r="200" fill="#fdd" stroke="none"></circle>
</svg>

但是有的时候,我们希望它和其它属性一样都使用中划线去进行定义,为了正常解析这类标签,vue提供了camel修饰符

.camel 修饰符允许在使用 DOM 模板时将 kebab-case property 转换为camelCase property,

在使用字符串模板或通过 vue-loader 编译时,无需使用 .camel,因为此时vue会帮助我们处理好。

<!--
   :view-box.camel 会被编译为 viewBox
    ps: 使用camel修饰符的时候,必须是在v-bind的情况下, :view-box.camel ===> viewBox
    如果没有结合v-bind,会被解析为 view-box.camel ===> view-box.camel
-->
<svg style="width:150px; height:300px" :view-box.camel="'0 0 400 400'">
  <circle cx="200" cy="200" r="200" fill="#fdd" stroke="none"></circle>
</svg>
<!-- 
    camel修饰符只会在svg标签元素上生效,在其它元素上时,camel修饰符会失效
    在本例中,:data-property.camel会被解析为dataproperty
-->
<div :data-property.camel="'value'">Hello Vue</div>