重学vue3 - 模板语法

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

data

data属性是传入一个函数,并且该函数需要返回一个对象

data中返回的对象会被Vue的响应式系统劫持,之后对该对象的修改或者访问都会在劫持中被处理

这也就是为什么可以在template中访问data中定义的数据,并且在data中对应数据发生改变的时候自动去修改界面

methods

methods属性是一个对象,通常我们会在这个对象中定义很多的方法

这些方法可以被绑定到模板中,并且可以使用this关键字来直接访问到data中返回的对象的属性

也就是说methods中的函数再被进行调用的时候

会通过bind方法将函数内部的this给绑定为data方法返回的那个对象的代理对象

所以methods中的方法不推荐定义为箭头函数,尤其是在函数内部需要使用this的时候

mustache语法

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

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

虽然vue也支持使用JSX来编写界面,但是在大多数情况下,使用基于HTML的模板语法

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

在底层的实现中,Vue将模板编译成虚拟DOM渲染函数

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

Mustache中不仅仅可以是data中的属性,也可以是一个JavaScript的表达式

<div id="app">
  <!-- mustache中可以使用data和methods等中定义的属性和方法 -->
  <h1>{{ count }}</h1>
  <!-- mustache可以很好的和原生html结构进行结合 -->
  <h2>count: {{ count }}</h2>
  <!-- mustache中支持任何的合法的JS表达式 -->
  <div>{{ count % 2 ? 'even' : 'odd' }}</div>
  <div>{{ changeCount(10) }}</div>
</div>

<script>
  Vue.createApp({
    data() {
      return {
        count: 100
      }
    },
    methods: {
      changeCount(step) {
        return this.count + step
      }
    },
  }).mount('#app')
</script>

指令

名称 说明
v-once 1. v-once用于指定元素或者组件只渲染一次
2. 当数据发生变化时,元素或者组件以及其所有的子元素将视为静态内容并且跳过
3. 该指令可以用于性能优
v-memo 1. 记住一个模板的子树。元素和组件上都可以使用
2. 该指令接收一个固定长度的数组作为依赖值进行记忆比对
3. 如果数组中的每个值都和上次渲染的时候相同,则整个该子树的更新会被跳过
4. 带有空依赖数组的 v-memo (v-memo="[]") 在功能上等效于 v-once
v-text 1. 用于更新元素的 textContent
2. v-text中的内容会覆盖掉元素原本的textContent
3. v-text没有mustache语法灵活,所以一般使用mustache语法来替换v-text
v-html 1. 默认情况下,如果我们展示的内容本身是 html 的,那么vue并不会对其进行特殊的解析
2. 如果我们希望这个内容被Vue可以解析出来,那么可以使用 v-html 来展示
3. 为了避免XSS攻击,请确保需要解析的html内容为安全有效的html内容
v-pre 1. v-pre用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签
2. 跳过不需要编译的节点,加快编译的速度
v-cloak 1. 这个指令保持在元素上直到关联组件实例结束编译
2. 当元素还未被解析完成时,其对应元素会存在属性v-cloak
和 CSS 规则如 [v-cloak] { display: none } 一起用时
这个指令可以隐藏未编译的 Mustache 标签直到组件实例准备完毕
v-bind v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值
v-on 方法的动态绑定

v-once

<!-- 指令可以看出是一种特殊的元素属性 -->
<div v-once>
  <h1>{{ name }}</h1>
  <div>{{ count }}</div>
</div>

v-memo

<div id="app">
  <!-- 此时当变量name 和 age的值发生改变的时候,对应内容会更新 -->
  <!-- 当height对应的值发生改变的时候,对应的内容并不会进行任何的更新 -->
  <div v-memo="[name, age]">
    <div>{{ name }}</div>
    <div>{{ age }}</div>
    <div>{{ height }}</div>
  </div>

  <button @click="changeName">changeName</button>
  <button @click="changeHeight">changeHeight</button>
</div>

<script>
  Vue.createApp({
    data() {
      return {
        name: 'Klaus',
        age: 23,
        height: '1.88'
      }
    },
    methods: {
      changeName() {
        this.name = 'Alex'
      },
      changeHeight() {
        this.height = '2.00'
      }
    },
  }).mount('#app')
</script>

v-text

<div>{{ name }}</div>
<!-- 等价于 -->
<div v-text="name"></div>

v-html

<!-- htmlContent: '<h1>this is h1 title</h1>' -->
<div v-html="htmlContent"></div>

v-pre

<div v-pre>
  <h1>{{ name }}</h1>
  <div>{{ count }}</div>
</div>

v-cloak

<style>
  [v-cloak] {
    display: none;
  }
</style>

<div id="app">
  <div v-cloak>{{ count }}</div>
</div>

<script>
  setTimeout(() => {
    Vue.createApp({
      data() {
        return {
          count: 100
        }
      }
    }).mount('#app')
  }, 3000)
</script>

v-bind

基本使用

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

<!-- v-bind 存在对应的语法糖 为 : -->
<img :src="imgUrl" />

绑定class

<!-- 普通方式进行绑定 -->
<!-- 在data选项中 -> classObj: 'active hover foo' -->
<div :class="classObj">foo</div>

<!-- class中也可以编写对应的表达式 -->
<div :class="isActive ? 'active' : ''">foo</div>

<!-- 
	动态绑定class对应的值的结果如果为boolean类型值,那么对应的结果会自动忽略
  所以这种方式的写法和三目运算符写法的作用是一致的,但是因为使用了vue的容错机制,所以并不推荐
-->
<div :class="isActive && 'active'">foo</div>

<!-- vue中的class编写支持对象写法 -->
<!--  
	对象的key --- class属性名
	对象的value --- 必须是一个boolean类型值
						 --- 如果值为true的时候,显示对应的class
						 --- 如果值为false的时候,不显示对应的class
-->
<div :class="{ active: isActive, hover: isHover }">foo</div>

<!--
	既然对象语法动态绑定class 对应的值 是 对象形式
	所以我们可以将对应的值 抽离到data选项中,或者methods选项中
-->

<!-- data选项中 fooClass: { active: this.isActive } -->
<div :class="fooClass">foo</div>

<!-- methods选项中 getFooClass() { return { active: this.isActive }  } -->
<div :class="getFooClass()">foo</div>

<!-- 动态绑定的class 可以和 普通的class 共存 -->
<div class="foo" :class="{ active: isActive }">foo</div>
<!-- 动态绑定class 除了对象语法外 也有数组语法 -->
<div :class="['active', 'foo']">foo</div>

<!-- 数组语法中可以传入变量 -->
<div :class="['active', foo]">foo</div>

<!-- 数组语法中,也可以编写合法的js表达式 -->
<div :class="[isActive ? 'active' : '', 'foo']">foo</div>

<!-- 数组语法中,可以嵌套使用对象语法 -->
<div :class="[{ active: isActive }, 'foo']">foo</div>

<!-- 数组语法可以和普通class 共存 -->
<div class="foo" :class="[{ active: isActive }]">foo</div>

绑定style

我们可以利用v-bind:style来绑定一些CSS内联样式,因为某些样式我们需要根据数据动态来决定,比如某段文字的颜色,大小等等

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

<!-- 使用style绑定对象 也是支持数组写法和对象写法的 -->
<!-- 
	基本使用方式和动态绑定class的用法是一致的
  在对象中可以使用变量,任意合法的js表达式
  或者可以将整个对象单独抽离后,在进行引用
-->
<div :style="{ color: 'red', 'font-size': fontSize + 'px' }">foo</div>

<!-- 
	动态绑定style 也是支持 数组写法的
  数组写法可以将多个样式对象应用到同一个元素上
-->
<div :style="[{ color: 'red' }, { fontSize: '30px' }]">foo</div>

动态绑定属性

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

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

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

<div :[propName]="foo">foo</div>

绑定一个对象

如果我们希望将一个对象的所有属性依次绑定到元素(或组件)上时,我们可以直接使用 v-bind 绑定一个对象

vue在解析的时候,会自动遍历对应的对象中的属性名和属性值,并依次作为属性添加到对应的组件或元素上

<!-- 在data选项中 info: { name: 'Klaus', age: 24 } -->
<!-- 直接使用v-bind 即可 不需要加上对应属性名 因为这里是绑定多个属性 -->
<div v-bind="info">foo</div>

<!-- 简写形式 - 不推荐,可读性较差 -->
<div :="info">foo</div>

<!-- 上述的写法等价于 -->
<div :name="info.name" :age="info.age">foo</div>

v-on

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

此时我们可以使用v-on指令来监听用户发生的事件,比如点击、拖拽、键盘事件等等

<div id="app">
  <!-- 基本使用 -->
  <div v-on:click="handleClick"></div>

  <!-- 简写方式 -->
  <div @mousemove="handleMove"></div>

  <!-- 可以通过这个方式绑定多个事件 -->
  <div @click="handleClick" @mousemove="handleMove"></div>
  <!-- 也可以通过这个当时绑定多个事件 -->
  <div v-on="{ click: handleClick, mousemove: handleMove }"></div>
  <!-- 或使用简写方式(可读性较差,不推荐) -->
  <div @="{ click: handleClick, mousemove: handleMove }"></div>

  <!--
如果事件逻辑简单,可以将其以表达式的方式绑定到元素上(可读性差,不推荐)
在模板中,可以直接访问声明的数据状态,方法等
-->
  <div @click="count++">{{ count }}</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.min.js"></script>
<script>
  Vue.createApp({
    data() {
      return {
        count: 0
      }
    },
    methods: {
      handleClick() {
        console.log('handleClick')
      },
      handleMove() {
        console.log('handleMove')
      }
    }
  }).mount('#app')

参数传递

<div id="app">
  <!-- 在没有参数需要传递的时候 直接输入对应的函数引用地址 -->
  <div @click="handleClick"></div>

  <!--
在需要传递参数的时候, 直接在函数名后通过小括号的形式进行调用
vue会在该函数外进行包裹,确保其在事件执行的时候才会被触发 (fun(p1, p1) -> () => { fun(p1, p2) })
如果我们自己传递了对应的参数,那么默认就不会在传递对应的事件对象
如果我们需要在传递参数的同时使用事件对象,可以使用内置对象$event
-->
  <div @click="handleParamsClick('Klaus', 18, $event)"></div>
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.min.js"></script>
<script>
  Vue.createApp({
    methods: {
      // 在没有参数的情况下 默认情况下vue会将对应的事件对象作为参数传递进来
      handleClick(e) {
        console.log(e)
      },

      handleParamsClick(name, age, event) {
        console.log(name, age, event)
      }
    }
  }).mount('#app')

修饰符

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

修饰符 说明
.stop 调用 event.stopPropagation()
.prevent 调用 event.preventDefault()
.capture 添加事件侦听器时使用 capture 模式
.self 只当事件是从侦听器绑定的元素本身触发时才触发回调
.{keyAlias} (例如: .enter) 仅当事件是从特定键触发时才触发回调
.once 只触发一次回调
.left 只当点击鼠标左键时触发
.middle 只当点击鼠标中键时触
.right 只当点击鼠标右键时触发
.passive { passive: true } 模式添加侦听器

条件渲染

在某些情况下,我们需要根据当前的条件决定某些元素或组件是否渲染,此时就可以使用条件渲染

<div id="app">
  <div v-if="users.length > 1">有多个嘉宾</div>
  <div v-else="users.length === 1">只有一个嘉宾</div>
  <div v-else>没有嘉宾</div>
</div>

v-if 的渲染是惰性

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

template

如果我们需要在多个元素上添加相同的指令,例如

<h1 v-if="showInfo">Klaus</h1>
<h1 v-if="showInfo">24</h1>

<!-- 渲染后的结果为 -->
<h1>Klaus</h1>
<h1>24</h1>

此时在每个元素上添加相同指令必然是十分繁琐的,所以我们会使用一个div元素进行包裹

目的是为了将其中的那些元素,作为div的子元素进行统一管理

<div v-if="showInfo">
  <h1>Klaus</h1>
  <h1>24</h1>
</div>

<!-- 渲染后的结果为 -->
<div>
  <h1>Klaus</h1>
  <h1>24</h1>
</div>

但是这么做,依旧存在一个很大的弊端,也就是我们额外引入了一个div元素

很多情况下,在渲染的时候,我们并不希望渲染这个额外的div元素

此时我们可以使用template元素

template元素可以当做不可⻅的包裹元素,一般和指令结合使用,在最终的渲染结构中,template并不会被最终渲染出来

<template v-if="showInfo">
	<h1>Klaus</h1>
	<h1>24</h1>
</template>

<!-- 渲染后的结果为 -->
<h1>Klaus</h1>
<h1>24</h1>

猜你喜欢

转载自juejin.im/post/7126151216765075493