渐进式 JavaScript 框架 Vue 3 备忘清单的快速参考列表,包含常用 API 和示例
Vue 是一套用于构建用户界面的渐进式框架
注意:Vue 3.x 版本对应 Vue Router 4.x 路由版本
已安装 16.0
或更高版本的 Node.js
$ npm init vue@latest
指令将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具
✔ Project name: … <your-project-name>
✔ Add TypeScript? … No/Yes
✔ Add JSX Support? … No/Yes
✔ Add Vue Router for Single Page Application development? … No/Yes
✔ Add Pinia for state management? … No/Yes
✔ Add Vitest for Unit testing? … No/Yes
✔ Add Cypress for both Unit and End-to-End testing? … No/Yes
✔ Add ESLint for code quality? … No/Yes
✔ Add Prettier for code formatting? … No/Yes
Scaffolding project in ./<your-project-name>...
Done.
安装依赖并启动开发服务器
$ cd <your-project-name>
$ npm install
$ npm run dev
当你准备将应用发布到生产环境时,请运行:
$ npm run build
此命令会在 ./dist
文件夹中为你的应用创建一个生产环境的构建版本
import { createApp, ref } from 'vue'
const app = createApp({
setup() {
const message = ref("Hello Vue3")
return {
message
}
}
})
app.mount('#app')
挂载应用
<div id="app">
<button @click="count++">
{{ count }}
</button>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<div id="app">{{ message }}</div>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
const message = ref("Hello Vue3")
return {
message
}
}
}).mount('#app')
</script>
<div id="app">{{ message, ref }}</div>
<script type="module">
import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
createApp({
setup() {
const message = ref("Hello Vue3")
return {
message
}
}
}).mount('#app')
</script>
<span>Message: {{ msg }}</span>
使用的是 Mustache
语法 (即双大括号),每次 msg
属性更改时它也会同步更新
<p>Using text interpolation: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
双大括号{{}}
会将数据解释为纯文本,使用 v-html
指令,将插入 HTML
<div v-bind:id="dynamicId"></div>
简写
<div :id="dynamicId"></div>
<button :disabled="isButtonDisabled">
Button
</button>
通过不带参数的 v-bind
,你可以将它们绑定到单个元素上
<script setup>
import comp from "./Comp.vue"
import {ref} from "vue"
const a = ref("hello")
const b = ref("world")
</script>
<template>
<comp v-bind="{a, b}"></comp>
</template>
如果你是使用的 setup
语法糖。需要使用 defineprops
声名(可以直接使用a
/b
)
const props = defineProps({
a: String,
b: String
})
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div :id="`list-${id}`"></div>
<!-- 这是一个语句,而非表达式 -->
{{ var a = 1 }}
<!-- 条件控制也不支持,请使用三元表达式 -->
{{ if (ok) { return message } }}
<span :title="toTitleDate(date)">
{{ formatDate(date) }}
</span>
<p v-if="seen">Now you see me</p>
<a v-bind:href="url"> ... </a>
<!-- 简写 -->
<a :href="url"> ... </a>
<a v-on:click="doSomething"> ... </a>
<!-- 简写 -->
<a @click="doSomething"> ... </a>
<a v-bind:[attributeName]="url"> ... </a>
<!-- 简写 -->
<a :[attributeName]="url"> ... </a>
这里的 attributeName
会作为一个 JS 表达式被动态执行
<a v-on:[eventName]="doSomething"> ... </a>
<!-- 简写 -->
<a @[eventName]="doSomething">
<form @submit.prevent="onSubmit">
...
</form>
.prevent
修饰符会告知 v-on
指令对触发的事件调用 event.preventDefault()
v-on:submit.prevent="onSubmit"
──┬─ ─┬──── ─┬───── ─┬──────
┆ ┆ ┆ ╰─ Value 解释为JS表达式
┆ ┆ ╰─ Modifiers 由前导点表示
┆ ╰─ Argument 跟随冒号或速记符号
╰─ Name 以 v- 开头使用速记时可以省略
<div>{{ state.count }}</div>
import { defineComponent, reactive } from 'vue';
// `defineComponent`用于IDE推导类型
export default defineComponent({
// setup 用于组合式 API 的特殊钩子函数
setup() {
const state = reactive({ count: 0 });
// 暴露 state 到模板
return {
state
};
},
});
<button @click="increment">
{{ state.count }}
</button>
import { defineComponent, reactive } from 'vue';
export default defineComponent({
setup() {
const state = reactive({ count: 0 });
function increment() {
state.count++;
}
// 不要忘记同时暴露 increment 函数
return {
state,
increment
};
},
})
<script setup>
setup语法糖<script setup>
import { reactive } from 'vue';
const state = reactive({ count: 0 })
function increment() {
state.count++
}
</script>
<template>
<button @click="increment">
{{ state.count }}
</button>
</template>
setup
语法糖用于简化代码,尤其是当需要暴露的状态和方法越来越多时
ref()
定义响应式变量reactive
只能用于对象、数组和 Map
、Set
这样的集合类型,对 string、number 和 boolean 这样的原始类型则需要使用ref
import { ref } from 'vue';
const count = ref(0);
console.log(count); // { value: 0 }
console.log(count.value); // 0
count.value++;
console.log(count.value); // 1
const objectRef = ref({ count: 0 });
// 这是响应式的替换
objectRef.value = { count: 1 };
const obj = {
foo: ref(1),
bar: ref(2)
};
// 该函数接收一个 ref
// 需要通过 .value 取值
// 但它会保持响应性
callSomeFunction(obj.foo);
// 仍然是响应式的
const { foo, bar } = obj;
在 html 模板中不需要带 .value
就可以使用
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>
<template>
<div>
{{ count }}
</div>
</template>
import { reactive, defineComponent, onUnmounted } from 'vue';
import { debounce } from 'lodash-es';
export default defineComponent({
setup() {
// 每个实例都有了自己的预置防抖的处理函数
const debouncedClick = debounce(click, 500);
function click() {
// ... 对点击的响应 ...
}
// 最好是在组件卸载时
// 清除掉防抖计时器
onUnmounted(() => {
debouncedClick.cancel();
});
},
});
<script setup>
import { ref } from 'vue'
const open = ref(false);
</script>
<template>
<button @click="open = !open">Toggle</button>
<div>Hello Vue!</div>
</template>
<style scope>
div{
transition: height 0.1s linear;
overflow: hidden;
height: v-bind(open ? '30px' : '0px');
}
</style>
<script setup>
import { ref, watch } from 'vue';
const count = ref(0)
const isEvent = ref(false)
function increment() {
state.count++
}
watch(count, function() {
isEvent.value = count.value % 2 === 0
})
</script>
<template>
<button @click="increment">
{{ count }}
</button>
<p>
is event: {{ isEvent ? 'yes' : 'no' }}
</p>
</template>
watch(count, function() {
isEvent.value = count.value % 2 === 0
}, {
// 上例中的 watch 不会立即执行,导致 isEvent 状态的初始值不准确。配置立即执行,会在一开始的时候立即执行一次
immediate: true
})
<script setup>
import { ref, computed } from 'vue';
const text = ref('')
// computed 的回调函数里,会根据已有并用到的状态计算出新的状态
const capital = computed(function(){
return text.value.toUpperCase();
})
</script>
<template>
<input v-model="text" />
<p>to capital: {{ capital }}</p>
</template>
<script setup>
import { defineProps } from 'vue';
// 这里可以将 `username` 解构出来,
// 但是一旦解构出来再使用,就不具备响应式能力
defineProps({
username: String
})
</script>
<template>
<p>username: {{ username }}</p>
</template>
子组件定义需要的参数
<script setup>
const username = 'vue'
</script>
<template>
<children :username="username" />
</template>
父组件参入参数
<script setup>
import { defineEmits, ref } from 'vue';
const emit = defineEmits(['search'])
const keyword = ref('')
const onSearch = function() {
emit('search', keyword.value)
}
</script>
<template>
<input v-model="keyword" />
<button @click="onSearch">search</button>
</template>
子组件定义支持 emit
的函数
<script setup>
const onSearch = function(keyword){
console.log(keyword)
}
</script>
<template>
<children @search="onSearch" />
</template>
父组件绑定子组件定义的事件
<script setup>
import { defineExpose, ref } from 'vue';
const keyword = ref('')
const onSearch = function() {
console.log(keyword.value)
}
defineExpose({ onSearch })
</script>
<template>
<input v-model="keyword" />
</template>
子组件对父组件暴露方法
<script setup>
import { ref } from 'vue'
const childrenRef = ref(null)
const onSearch = function() {
childrenRef.value.onSearch()
}
</script>
<template>
<children ref='childrenRef' />
<button @click="onSearch">search</button>
</template>
父组件调用子组件的方法
import type { InjectionKey, Ref } from 'vue'
export const ProvideKey = Symbol() as InjectionKey<Ref<string>>
在应用中使用 ProvideKey
<script setup lang="ts">
import { provide, ref } from 'vue'
import { ProvideKey } from './types'
const text = ref<string>('123')
provide(ProvideKey, text)
</script>
<template>
<input v-model="text" />
</template>
父组件为后代组件提供数据
<script setup lang="ts">
import { inject } from 'vue'
import { ProvideKey } from './types'
const value = inject(ProvideKey)
</script>
<template>
<h4>{{value}}</h4>
</template>
后代组件注入父组件提供的数据
当使用 <script setup>
时,defineProps()
宏函数支持从它的参数中推导类型
<script setup lang="ts">
const props = defineProps({
foo: { type: String, required: true },
bar