Vue3书写风格

Vue3支持三种书写风格

选项式API(Options API)

Vue2的写法

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
<script>
export default {
// data() 返回的属性将会成为响应式的状态
// 并且暴露在 `this` 上
data() {
return {
count: 0
}
},

// methods 是一些用来更改状态与触发更新的函数
// 它们可以在模板中作为事件监听器绑定
methods: {
increment() {
this.count++
}
},

// 生命周期钩子会在组件生命周期的各个不同阶段被调用
// 例如这个函数就会在组件挂载完成后被调用
mounted() {
console.log(`The initial count is ${this.count}.`)
}
}
</script>

<template>
<button @click="increment">Count is: {{ count }}</button>
</template>

组合式API(Composition API)

又称setup函数形式

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
<script>
import { setup, ref, onMounted } from 'vue'

export default {
setup() {
// 响应式状态
const count = ref(0)

// 用来修改状态、触发更新的函数
function increment() {
count.value++
}

// 生命周期钩子
onMounted(() => {
console.log(`The initial count is ${count.value}.`)
})

// 必须将数据return出去,这样才能被展示
return {
count
}
}
}
</script>

<template>
<button @click="increment">Count is: {{ count }}</button>
</template>

setup语法糖模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script setup>
import { ref, onMounted } from 'vue'

// 响应式状态
// 不需要return,直接可以被展示
const count = ref(0)

// 用来修改状态、触发更新的函数
function increment() {
count.value++
}

// 生命周期钩子
onMounted(() => {
console.log(`The initial count is ${count.value}.`)
})
</script>

<template>
<button @click="increment">Count is: {{ count }}</button>
</template>

模板语法

template中可以使用插值语法{{ xxx }},可以用变量、简单的运算、API调用等展示内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<!-- 编译成<div>1</div> -->
<div>{{ a }}</div>
<!-- 编译成<div>2</div> -->
<div>{{ a + 1 }}</div>
<!-- 编译成<div>true</div> -->
<div>{{ a? "true": "false" }}</div>
<!-- 编译成<div>[{"num":1},{"num":2},{"num":3},{"num":4},{"num":5}]</div> -->
<div>{{ b.map(value=>({num:v}) }}</div>
</template>

<script setup>
const a = 1
const b = [1,2,3,4,5]
</script>

Vue指令

“v-“开头的都是vue的(内置)指令,可以直接使用

  • v-text:显示文本

    1
    2
    3
    4
    5
    6
    7
    8
    <template>
    <!-- 编译成<div>我是一段文字</div> -->
    <div v-text="a"></div>
    </template>

    <script setup>
    const a = "我是一段文字"
    </script>
  • v-html:展示富文本,但不支持组件

    1
    2
    3
    4
    5
    6
    7
    8
    <template>
    <!-- 编译成<div><section style='color:red;'>我是一段文字</section></div> -->
    <div v-html="a"></div>
    </template>

    <script setup>
    const a = "<section style='color:red;'>我是一段文字</section>"
    </script>
  • v-if:控制元素的显示隐藏(切换真假DOM)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <template>
    <!-- a为真值时才是DOM节点,否则会变成注释节点 -->
    <!-- 当应用在组件上时,v-if和v-show会有区别 -->
    <div v-if="a">true</div>
    </template>

    <script setup>
    const a = true
    </script>
  • v-else-ifv-if的“else if块”,可以链式调用

  • v-else:v-if条件收尾语句

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <template>
    <!-- 编译成<div>C</div> -->
    <div v-if="a == 'A'">A</div>
    <div v-else-if="a == 'B'">B</div>
    <div v-else>C</div>
    </template>

    <script setup>
    const a = "C"
    </script>
  • v-show:控制元素的显示隐藏(css display none和block切换)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <template>
    <!-- a为真值时display为block,否则为none -->
    <!-- 因此v-show比v-if性能更高,因为它只是切换一下css -->
    <div v-show="a">true</div>
    </template>

    <script setup>
    const a = true
    </script>
  • v-on:简写为@,给元素添加事件

    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
    41
    <template>
    <!-- 这两种写法是等价的 -->
    <button v-on:click="a">click me</button>
    <button @click="a">click me</button>

    <!-- 支持动态事件名 -->
    <button @[event]="a">click me</button>

    <!-- 支持修饰符 -->
    <div @click="parent">
    <!-- 阻止冒泡 -->
    <button @[event].stop="a">click me</button>
    <!-- 开启事件捕获 -->
    <button @[event].capture="a">click me</button>
    <!-- 阻止默认事件 -->
    <button @[event].prevent="a">click me</button>
    <!-- 只能发生一次 -->
    <button @[event].once="a">click me</button>
    <!-- 当event.target为元素本身时才触发 -->
    <button @[event].self="a">click me</button>
    <!-- 永不阻止默认事件 -->
    <button @scroll.self="b">scroll me</button>
    <!-- 可以链式调用,需要注意顺序 -->
    <button @[event].prevent.self="a">click me</button>
    <button @[event].self.prevent="a">click me</button>
    <!-- 还有很多别的修饰符,https://cn.vuejs.org/guide/essentials/event-handling.html#event-modifiers -->
    </div>
    </template>

    <script setup>
    const a = ()=> {
    console.log("click")
    }
    const b = ()=> {
    console.log("scroll")
    }
    const event = "click"
    const parent = ()=> {
    console.log("click parent")
    }
    </script>
  • v-bind:简写为:,绑定元素的属性

    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
    <template>
    <!-- 这两种写法是等价的 -->
    <div v-bind:id="a">演示v-bind:id</div>
    <div :id="a">演示:id</div>
    <!-- 这两种写法是等价的 -->
    <div :style="style">演示:style</div>
    <div :class="['a','b']">演示:style</div>

    <!-- 可以使用表达式 -->
    <div :class="[b? 'a': 'b']">演示:style</div>

    <!-- 可以同时支持一个动态、一个静态 -->
    <!-- 不能支持多个动态或多个静态 -->
    <div :class="[b? 'a': 'b']" class="c">演示:style</div>
    </template>

    <script setup>
    const a = 114514
    const b = true
    const style = {
    color:"red";
    border:"1px solid black"
    }
    </script>

    <style>
    .a {
    color: red;
    }
    .b {
    border: 1px solid black;
    }
    .c {
    background-color: pink;
    }
    </style>
  • v-model:双向绑定表单元素

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <template>
    <div>
    <input v-model="name" type="text" />
    <div>{{ name }}</div>
    </div>
    </template>

    <script setup>
    // 使用ref或reactive包裹的变量才具有响应式
    import { ref } from "vue"

    const name = ref("野兽先辈")
    </script>
  • v-for:遍历元素

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <template>
    <div>
    <!-- item:数组元素 index:元素下标 -->
    <!-- v-for可以嵌套 -->
    <!-- 需要给v-for提供一个key(唯一值) -->
    <div :key="index" v-for="(item, index) in name">{{ index }} - {{ item }}</div>
    </div>
    </template>

    <script setup>
    const name = ["野兽先辈", "MUR", "KMR", "远野", "野兽妹"]
    </script>
  • v-once:性能优化,只渲染一次

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <template>
    <!-- 改变a的值也不会发生变化 -->
    <div v-once>{{ a }}</div>
    <button @click="a++">+</button>
    </template>

    <script setup>
    import { ref } from "vue"

    const a = ref(1)
    </script>
  • v-memo:大型项目性能优化

    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
    <template>
    <!-- 写一个空数组时,效果就和v-once一样 -->
    <div v-memo="[]">{{ a }}</div>
    <button @click="a++">+</button>

    <!-- 常配合v-for使用,条件成立时才会更新,节省小部分性能 -->
    <div @click="select(item.id)" :key="item.id" v-for="(item) in arr" v-memo="[item.id === active]">
    {{ item.id }} - selected: {{ item.id == active }}
    </div>
    </template>

    <script setup>
    import { ref } from "vue"

    const a = ref(1)

    import { ref, reactive } from 'vue'

    const arr = reactive<any[]>([])
    for (let i = 0; i < 10000; i++) {
    arr.push({
    id: i + 1,
    name: "test"
    })
    }

    const active = ref(1)

    const select = async (index: number) => {
    active.value = index;
    console.time()
    await Promise.resolve()
    console.timeEnd()
    }
    </script>