Skip to content

0x00a-Vue3用法拾遗

模板语法

v-bind

html
<div v-bind:id="dynamicId"></div>

<div :id="dynamicId"></div>
<div v-bind:id="dynamicId"></div>

<div :id="dynamicId"></div>

如果是vue在3.4版本以上,若 html attribute 的名称与绑定的 JavaScript 值的名称相同,可以省略等号,例如:

html
<div v-bind:id="id"></div>

<div :id></div>
<div v-bind:id="id"></div>

<div :id></div>

动态绑定

html
<!--
注意,参数表达式有一些约束,
参见下面“动态参数值的限制”与“动态参数语法的限制”章节的解释
-->
<a v-bind:[attributeName]="url"> ... </a>

<!-- 简写 -->
<a :[attributeName]="url"> ... </a>
<!--
注意,参数表达式有一些约束,
参见下面“动态参数值的限制”与“动态参数语法的限制”章节的解释
-->
<a v-bind:[attributeName]="url"> ... </a>

<!-- 简写 -->
<a :[attributeName]="url"> ... </a>

相似地,你还可以将一个函数绑定到动态的事件名称上:

html
<a v-on:[eventName]="doSomething"> ... </a>

<!-- 简写 -->
<a @[eventName]="doSomething"> ... </a>
<a v-on:[eventName]="doSomething"> ... </a>

<!-- 简写 -->
<a @[eventName]="doSomething"> ... </a>

响应式基础

ref

js
<script setup>
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 0
</script>

<template>
  <h1>{{ count }}</h1>  
  <button @click="count++"> Click Me</button>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 0
</script>

<template>
  <h1>{{ count }}</h1>  
  <button @click="count++"> Click Me</button>
</template>

1). <script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖,以上代码相当于:

js
import { ref } from 'vue'
export default {
  setup() {
    const count = ref(0)   
    return {
      count
    }
  }
}
import { ref } from 'vue'
export default {
  setup() {
    const count = ref(0)   
    return {
      count
    }
  }
}

2). 在组合式 API 中,推荐使用 ref() 函数来声明响应式状态。ref() 接收参数,并将其包裹在一个带有 .value 属性的 ref 对象中返回。
3). 在模板中使用 ref 时,我们需要附加 .value

ref 深层

Ref 可以持有任何类型的值,包括深层嵌套的对象、数组或者 JavaScript 内置的数据结构,比如 Map

非原始值将通过 reactive() 转换为响应式代理。

Ref 会使它的值具有深层响应性。这意味着即使改变嵌套对象或数组时,变化也会被检测到

js
<script setup>
import { ref} from 'vue';
const obj = ref({
  nested: { count: 0 },
  arr: ['foo', 'bar']
})
const addCount = () => {
  obj.value.nested.count++;
}
</script>

<template>
  <p>{{ obj.arr }}</p>
  <p>{{ obj.nested.count }}</p>
  <button @click="addCount">click to add count</button>
</template>
<script setup>
import { ref} from 'vue';
const obj = ref({
  nested: { count: 0 },
  arr: ['foo', 'bar']
})
const addCount = () => {
  obj.value.nested.count++;
}
</script>

<template>
  <p>{{ obj.arr }}</p>
  <p>{{ obj.nested.count }}</p>
  <button @click="addCount">click to add count</button>
</template>

reactive()

还有另一种声明响应式状态的方式,即使用 reactive() API。与将内部值包装在特殊对象中的 ref 不同,reactive() 将使对象本身具有响应性:

js
import { reactive } from 'vue'
const state = reactive({ count: 0 })
import { reactive } from 'vue'
const state = reactive({ count: 0 })

获取原始值

toRaw() 可以返回由 reactive()readonly()shallowReactive() 或者 shallowReadonly() 创建的代理对应的原始对象。

js
const result = toRaw(xx);
const result = toRaw(xx);

使用JSON序列化也可以: JSON.parse(JSON.stringify(xxx))

计算属性

若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 author.books 不改变,无论多少次访问 publishedBooksMessage 都会立即返回先前的计算结果,而不用重复执行 getter 函数。

js
import { reactive, computed } from 'vue'

const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})
const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})
import { reactive, computed } from 'vue'

const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})
const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})

计算属性的getter、setter

js
<script setup>
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  // getter
  get() {
    return firstName.value + ' ' + lastName.value
  },
  // setter
  set(newValue) {
    // 注意:我们这里使用的是解构赋值语法
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})
</script>
<script setup>
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  // getter
  get() {
    return firstName.value + ' ' + lastName.value
  },
  // setter
  set(newValue) {
    // 注意:我们这里使用的是解构赋值语法
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})
</script>

Q&A

如何进行动态图片引入

https://stackoverflow.com/questions/66419471/vue-3-vite-dynamic-image-src

  1. 静态路径
js
<script setup>
import imageUrl from '@/assets/images/logo.svg' // => or relative path
</script>

<template>
  <img :src="imageUrl" alt="img" />
</template>
<script setup>
import imageUrl from '@/assets/images/logo.svg' // => or relative path
</script>

<template>
  <img :src="imageUrl" alt="img" />
</template>
  1. 动态路径
js
<script setup>
const imageUrl = new URL(`./dir/${name}.png`, import.meta.url).href
</script>

<template>
  <img :src="imageUrl" alt="img" />
</template>
<script setup>
const imageUrl = new URL(`./dir/${name}.png`, import.meta.url).href
</script>

<template>
  <img :src="imageUrl" alt="img" />
</template>

为什么可以这么处理:

import.meta.url 是一个 ESM 的原生功能,会暴露当前模块的 URL。将它与原生的 URL 构造器 组合使用,在一个 JavaScript 模块中,通过相对路径我们就能得到一个被完整解析的静态资源 URL:
对于URL: 如果url参数是相对 URL,则构造函数将使用url参数和可选的base参数作为基础, 例如:

js
new URL('../cats', 'http://www.example.com/dogs').href;
// 得到: http://www.example.com/cats
new URL('../cats', 'http://www.example.com/dogs').href;
// 得到: http://www.example.com/cats
  1. 具有动态URL和绝对路径。 必须将别名@/替换为/src
js
<script setup>
const imageUrl = new URL('/src/assets/images/logo.svg', import.meta.url)
</script>

<template>
  <img :src="imageUrl" alt="img" />
</template>
<script setup>
const imageUrl = new URL('/src/assets/images/logo.svg', import.meta.url)
</script>

<template>
  <img :src="imageUrl" alt="img" />
</template>