添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

指令将会安装并执行 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 文件夹中为你的应用创建一个生产环境的构建版本

<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>
<p>Using text interpolation: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>

双大括号{{}}会将数据解释为纯文本,使用 v-html 指令,将插入 HTML

如果你是使用的 setup 语法糖。需要使用 defineprops 声名(可以直接使用a/b

const props = defineProps({
  a: String,
  b: String
<a v-bind:[attributeName]="url"> ... </a>
<!-- 简写 -->
<a :[attributeName]="url"> ... </a>

这里的 attributeName 会作为一个 JS 表达式被动态执行

v-on:submit.prevent="onSubmit"
──┬─ ─┬──── ─┬─────  ─┬──────
  ┆   ┆      ┆        ╰─ Value 解释为JS表达式
  ┆   ┆      ╰─ Modifiers 由前导点表示
  ┆   ╰─ Argument 跟随冒号或速记符号
  ╰─ Name 以 v- 开头使用速记时可以省略
// `defineComponent`用于IDE推导类型
export default defineComponent({
  // setup 用于组合式 API 的特殊钩子函数
  setup() {
    const state = reactive({ count: 0 });
    // 暴露 state 到模板
    return {
      state
});
import { defineComponent, reactive } from 'vue';
export default defineComponent({
  setup() {
    const state = reactive({ count: 0 });
    function increment() {
      state.count++;
    // 不要忘记同时暴露 increment 函数
    return {
      state,
      increment

reactive只能用于对象、数组和 MapSet 这样的集合类型,对 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>
    {{ 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();
    });
});
    transition: height 0.1s linear;
    overflow: hidden;
    height: v-bind(open ? '30px' : '0px');
</style>
  isEvent.value = count.value % 2 === 0
}, {
  // 上例中的 watch 不会立即执行,导致 isEvent 状态的初始值不准确。配置立即执行,会在一开始的时候立即执行一次
  immediate: true
const text = ref('')
// computed 的回调函数里,会根据已有并用到的状态计算出新的状态
const capital = computed(function(){
  return text.value.toUpperCase();
</script>
<template>
  <input v-model="text" />
  <p>to capital: {{ capital }}</p>
</template>
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>

父组件绑定子组件定义的事件

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: Number
props.foo // string
props.bar // number | undefined
</script>

对同一个文件中的一个接口或对象类型字面量的引用:

interface Props {/* ... */}
defineProps<Props>()
Props 解构默认值
export interface Props {
  msg?: string
  labels?: string[]
const props = withDefaults(defineProps<Props>(), {
  msg: 'hello',
  labels: () => ['one', 'two']

使用目前为实验性的响应性语法糖

<script setup lang="ts">
interface Props {
  name: string
  count?: number
// 对 defineProps() 的响应性解构
// 默认值会被编译为等价的运行时选项
const {
  name, count = 100
} = defineProps<Props>()
</script>
const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()
</script>
<script setup lang="ts">
function handleChange(event) {
  // `event` 隐式地标注为 `any` 类型
  console.log(event.target.value)
</script>
<template>
  <input
    type="text"
    @change="handleChange" />
</template>

显式地为事件处理函数的参数标注类型

function handleChange(event: Event) {
  const target = event.target as HTMLInputElement
  console.log(target.value)
import type { InjectionKey } from 'vue'
const key = Symbol() as InjectionKey<string>
// 若提供的是非字符串值会导致错误
provide(key, 'foo')
// foo 的类型:string | undefined
const foo = inject(key)
import { ref, onMounted } from 'vue'
const el = ref<HTMLInputElement | null>(null)
onMounted(() => {
  el.value?.focus()
</script>
<template>
  <input ref="el" />
</template>
const isContentShown = ref(false)
const open = 
      () => (isContentShown.value = true)
defineExpose({
</script>

使用 TypeScript 内置的 InstanceType 工具类型来获取其实例类

<!-- App.vue -->
<script setup lang="ts">
import MyModal from './MyModal.vue'
type Modal = InstanceType<typeof MyModal>
const modal = ref<Modal | null>(null)
const openModal = () => {
  modal.value?.open()
</script>
    id: [Number, String],
    msg: { type: String, required: true },
    metadata: null
  mounted() {
    // 类型:string | undefined
    this.name
    // 类型:number|string|undefined
    this.id
    // 类型:string
    this.msg
    // 类型:any
    this.metadata

使用 PropType 这个工具类型来标记更复杂的 props 类型

import { defineComponent } from 'vue'
import type { PropType } from 'vue'
interface Book {
  title: string
  author: string
  year: number
export default defineComponent({
  props: {
    book: {
      // 提供相对 `Object` 更确定的类型
      type: Object as PropType<Book>,
      required: true
    // 也可以标记函数
    callback: Function as PropType<(id: number) => void>
  mounted() {
    this.book.title // string
    this.book.year // number
    // TS Error: argument of type 'string' is not
    // assignable to parameter of type 'number'
    this.callback?.('123')
  methods: {
    handleChange(event: Event) {
      console.log((event.target as HTMLInputElement).value)
  interface ComponentCustomProperties {
    $http: typeof axios
    $translate: (key: string) => string
类型扩展的位置

我们可以将这些类型扩展放在一个 .ts 文件,或是一个影响整个项目的 *.d.ts 文件中

// 不工作,将覆盖原始类型。
declare module 'vue' {
  interface ComponentCustomProperties {
    $translate: (key: string) => string
// 正常工作。
export {}
declare module 'vue' {
  interface ComponentCustomProperties {
    $translate: (key: string) => string

某些插件,比如 vue-router,提供了一些自定义的组件选项,比如 beforeRouteEnter:

import { defineComponent } from 'vue'
export default defineComponent({
  beforeRouteEnter(to, from, next) {
    // ...

如果没有确切的类型标注,这个钩子函数的参数会隐式地标注为 any 类型。我们可以为 ComponentCustomOptions 接口扩展自定义的选项来支持:

import { Route } from 'vue-router'
declare module 'vue' {
  interface ComponentCustomOptions {
    beforeRouteEnter?(
      to: Route,
      from: Route,
      next: () => void
    ): void