模板语法
v-bind
<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 值的名称相同,可以省略等号,例如:
<div v-bind:id="id"></div>
或
<div :id></div>
<div v-bind:id="id"></div>
或
<div :id></div>
动态绑定
<!--
注意,参数表达式有一些约束,
参见下面“动态参数值的限制”与“动态参数语法的限制”章节的解释
-->
<a v-bind:[attributeName]="url"> ... </a>
<!-- 简写 -->
<a :[attributeName]="url"> ... </a>
<!--
注意,参数表达式有一些约束,
参见下面“动态参数值的限制”与“动态参数语法的限制”章节的解释
-->
<a v-bind:[attributeName]="url"> ... </a>
<!-- 简写 -->
<a :[attributeName]="url"> ... </a>
相似地,你还可以将一个函数绑定到动态的事件名称上:
<a v-on:[eventName]="doSomething"> ... </a>
<!-- 简写 -->
<a @[eventName]="doSomething"> ... </a>
<a v-on:[eventName]="doSomething"> ... </a>
<!-- 简写 -->
<a @[eventName]="doSomething"> ... </a>
响应式基础
ref
<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 的编译时语法糖,以上代码相当于:
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 会使它的值具有深层响应性。这意味着即使改变嵌套对象或数组时,变化也会被检测到:
<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()
将使对象本身具有响应性:
import { reactive } from 'vue'
const state = reactive({ count: 0 })
import { reactive } from 'vue'
const state = reactive({ count: 0 })
获取原始值
toRaw()
可以返回由 reactive()
、 readonly()
、 shallowReactive()
或者 shallowReadonly()
创建的代理对应的原始对象。
const result = toRaw(xx);
const result = toRaw(xx);
使用JSON序列化也可以: JSON.parse(JSON.stringify(xxx))
计算属性
若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 author.books
不改变,无论多少次访问 publishedBooksMessage
都会立即返回先前的计算结果,而不用重复执行 getter 函数。
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
<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
- 静态路径
<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>
- 动态路径
<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>
为什么可以这么处理:
i
mport.meta.url 是一个 ESM 的原生功能,会暴露当前模块的 URL。将它与原生的 URL 构造器 组合使用,在一个 JavaScript 模块中,通过相对路径我们就能得到一个被完整解析的静态资源 URL:
对于URL: 如果url
参数是相对 URL,则构造函数将使用url
参数和可选的base
参数作为基础, 例如:
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
- 具有动态URL和绝对路径。 必须将别名
@/
替换为/src
<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>