vue3-vite-语法大全

3 阅读11分钟

一、核心基础:<script setup> 完整基础语法(必背)

✅ 1. 组件结构(单文件组件 SFC 标准写法)

vue3-vite-demo 中所有 .vue 组件都是这个结构,重中之重,所有页面的基础

vue

<!-- src/components/xxx.vue -->
<template>
  <!-- HTML结构,直接写变量/方法名即可,无需this -->
  <div>{{ msg }}</div>
  <button @click="handleClick">点击</button>
</template>

<script setup>
  // Vue3组合式API 核心区域,所有逻辑写这里
  // 特点:无需export default、无需return、变量/方法自动暴露给template使用
  // 没有this!没有this!没有this!所有内容直接调用
</script>

<style scoped>
  /* scoped:样式只作用于当前组件,防止样式污染,必加 */
  /* lang="scss":需要安装sass依赖,npm i sass -D 即可使用 */
  div { color: red; }
</style>

✅ 2. 响应式数据定义(Vue3 核心,3 种常用方式)

响应式:数据变化时,页面视图自动更新,Vue3 废弃了 Vue2 的 data(){return{}},全部用组合式 API 定义,优先级:ref > reactive > readonly

vue

<script setup>
// 1. 引入核心API
import { ref, reactive, readonly } from 'vue'

// ✔ ref:定义【基本数据类型】 字符串/数字/布尔值 (最常用)
// 赋值/取值 必须加 .value (script里必须加,template里直接用变量名)
const num = ref(0)
const str = ref('Vue3+Vite')
const isShow = ref(true)
const token = ref('')
// 修改ref数据
num.value += 1
token.value = 'abc123xxx'

// ✔ reactive:定义【引用数据类型】 对象/数组 (常用)
// 赋值/取值 无需.value,直接操作,响应式深度绑定
const user = reactive({
  name: '张三',
  age: 20,
  info: { address: '北京' }
})
const list = reactive([
  { id: 1, name: 'vue3' },
  { id: 2, name: 'vite' }
])
// 修改reactive数据
user.name = '李四'
user.info.address = '上海'
list.push({ id:3, name:'axios' })

// ✔ readonly:定义【只读响应式数据】 只读不可修改
const readOnlyUser = readonly(user)
// readOnlyUser.name = '王五' → 报错,无法修改
</script>

<template>
  <div>{{ num }} {{ str }} {{ isShow }}</div>
  <div>{{ user.name }} {{ user.info.address }}</div>
  <div>{{ list }}</div>
</template>

✅ 核心区别记忆:ref 管基本类型,.value 是标识;reactive 管复杂类型,直接用

✅ 3. 方法定义 & 事件绑定(methods 替代方案)

Vue3 中没有 methods 选项,直接在 <script setup> 中定义普通函数即可,函数自动暴露给模板,模板中直接调用

vue

<script setup>
import { ref } from 'vue'
const count = ref(0)

// ✔ 定义普通方法
const addCount = () => {
  count.value++
}

// ✔ 定义带参数的方法
const setCount = (val) => {
  count.value = val
}

// ✔ 定义异步方法(axios请求/定时器/async-await)
const getList = async () => {
  // 异步请求示例
  // const res = await axios.get('/api/list')
  console.log('异步请求执行')
}
</script>

<template>
  <!-- 无参事件绑定 -->
  <button @click="addCount">点击+1</button>
  <!-- 有参事件绑定 -->
  <button @click="setCount(10)">设置为10</button>
  <!-- 异步方法调用 -->
  <button @click="getList">获取数据</button>
  <!-- 原生事件修饰符 跟Vue2用法一致 -->
  <button @click.stop="addCount">阻止冒泡</button>
  <input @keyup.enter="getList" /> <!-- 回车触发 -->
</template>

二、父子组件通信(高频!开发必用,4 种核心写法)

Vue3 组件通信是项目开发的核心,所有写法都是基于 <script setup> ,没有 this.$parent / this.$children,全部是官方推荐的标准化写法,按使用频率排序,覆盖所有业务场景

✅ 1. 父传子:defineProps (最常用,父组件给子组件传值)

子组件只读父组件传递的数据,不能直接修改 props,单向数据流原则

vue

<!-- 父组件 Parent.vue -->
<template>
  <Child :msg="parentMsg" :user="userInfo" :list="arr" />
</template>
<script setup>
import { ref, reactive } from 'vue'
import Child from './Child.vue' // 引入子组件(Vite中.vue后缀不能省略)
const parentMsg = ref('父组件传递的内容')
const userInfo = reactive({ name: '张三', age:20 })
const arr = reactive([1,2,3])
</script>

<!-- 子组件 Child.vue -->
<template>
  <!-- 直接使用props接收的变量 -->
  <div>{{ msg }}</div>
  <div>{{ user.name }}</div>
  <div>{{ list }}</div>
</template>
<script setup>
// ✔ 核心:defineProps 接收父组件传参,无需引入,Vue自动提供
// 写法1:简单声明(推荐,简洁)
const props = defineProps(['msg', 'user', 'list'])

// 写法2:带类型校验的声明(规范,项目推荐)
const props = defineProps({
  msg: String,
  user: Object,
  list: Array,
  num: {
    type: Number,
    default: 0, // 默认值
    required: false // 是否必传
  }
})

// script中使用props
console.log(props.msg)
console.log(props.user.name)
</script>

✅ 2. 子传父:defineEmits (最常用,子组件给父组件传值 / 触发事件)

子组件不能直接修改父组件数据,通过派发事件的方式通知父组件修改,完美遵循单向数据流

vue

<!-- 子组件 Child.vue -->
<template>
  <button @click="sendData">子组件传值给父组件</button>
  <button @click="sendNum(666)">传递数字</button>
</template>
<script setup>
// ✔ 核心:defineEmits 声明事件,无需引入,Vue自动提供
// 写法1:数组声明事件名
const emit = defineEmits(['sendMsg', 'sendNumber'])

// 写法2:对象声明(带参数校验,规范)
const emit = defineEmits({
  sendMsg: (val) => typeof val === 'string',
  sendNumber: (val) => typeof val === 'number'
})

// 子组件派发事件,携带参数
const sendData = () => {
  emit('sendMsg', '我是子组件的内容')
}
const sendNum = (num) => {
  emit('sendNumber', num)
}
</script>

<!-- 父组件 Parent.vue -->
<template>
  <!-- 父组件监听子组件的事件,接收参数 -->
  <Child @sendMsg="getMsg" @sendNumber="getNum" />
  <div>子组件传递的内容:{{ childMsg }}</div>
  <div>子组件传递的数字:{{ childNum }}</div>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const childMsg = ref('')
const childNum = ref(0)

// 父组件接收子组件的参数并处理
const getMsg = (val) => {
  childMsg.value = val
}
const getNum = (val) => {
  childNum.value = val
}
</script>

✅ 3. 父组件获取子组件的属性 / 方法:defineExpose (常用,子组件暴露内容)

Vue3 中 <script setup> 组件的内容是默认关闭暴露的,父组件无法直接获取子组件的变量 / 方法,必须通过 defineExpose 主动暴露,父组件用 ref 获取

vue

<!-- 子组件 Child.vue -->
<template>子组件</template>
<script setup>
import { ref } from 'vue'
// 子组件的变量和方法
const childNum = ref(999)
const childFn = () => {
  return '我是子组件的方法'
}

// ✔ 核心:defineExpose 暴露内容给父组件,无需引入
defineExpose({
  childNum,
  childFn
})
</script>

<!-- 父组件 Parent.vue -->
<template>
  <Child ref="childRef" />
  <button @click="getChildData">获取子组件内容</button>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
// ✔ 定义ref绑定子组件
const childRef = ref(null)

const getChildData = () => {
  // 获取子组件暴露的变量
  console.log(childRef.value.childNum) // 999
  // 调用子组件暴露的方法
  console.log(childRef.value.childFn()) // 我是子组件的方法
}
</script>

✅ 4. 祖孙组件通信:provide / inject (跨层级传值,无需逐层传递)

解决「父传子传孙」的多层级传参问题,父组件通过 provide 提供数据,子孙组件通过 inject 注入数据,无论层级多深都能获取,无需逐层 props 传递,非常实用

vue

<!-- 顶层父组件 Parent.vue -->
<template>
  <Child />
</template>
<script setup>
import { provide, ref } from 'vue'
import Child from './Child.vue'
// ✔ provide:提供数据,参数1=key,参数2=值(响应式)
const theme = ref('dark')
provide('themeColor', theme)
provide('title', 'Vue3+Vite教程')
</script>

<!-- 深层子组件 Grandson.vue(Child的子组件) -->
<template>
  <div>{{ themeColor }} {{ title }}</div>
</template>
<script setup>
import { inject } from 'vue'
// ✔ inject:注入数据,参数1=父组件的key,参数2=默认值(可选)
const themeColor = inject('themeColor')
const title = inject('title', '默认标题')
// 修改响应式数据,父组件也会同步更新
themeColor.value = 'light'
</script>

三、计算属性 & 监听器(核心 API,Vue3 写法)

✅ 1. 计算属性 computed - 依赖值变化自动更新,有缓存(推荐)

替代复杂的模板表达式,处理数据格式化、数据拼接、条件计算等,有缓存,依赖值不变时不会重复执行,性能优于方法

vue

<script setup>
import { ref, computed } from 'vue'
const num = ref(10)
const list = ref([1,2,3,4,5])

// ✔ 只读计算属性(最常用)
const doubleNum = computed(() => {
  return num.value * 2
})

// ✔ 可修改的计算属性(带get/set)
const fullName = computed({
  get() {
    return '张' + '三'
  },
  set(val) {
    console.log('修改了姓名:', val)
  }
})

// ✔ 复杂计算:过滤数组
const filterList = computed(() => {
  return list.value.filter(item => item > 2)
})
</script>

<template>
  <div>{{ doubleNum }}</div> <!-- 20 -->
  <div>{{ filterList }}</div> <!-- [3,4,5] -->
</template>

✅ 2. 监听器 watch - 监听数据变化,执行回调(4 种写法全覆盖)

Vue3 废弃了 Vue2 的 watch:{},改用组合式 API watch,功能更强大,支持监听单个值、多个值、深度监听、立即执行,无数据变化不执行,按需触发

vue

<script setup>
import { ref, reactive, watch } from 'vue'
const num = ref(0)
const user = reactive({ name: '张三', age:20 })
const list = ref([1,2,3])

// ✔ 写法1:监听单个ref数据(最常用)
watch(num, (newVal, oldVal) => {
  console.log('num变化了:', newVal, oldVal)
})

// ✔ 写法2:监听单个reactive对象(深度监听,自动开启,无需配置)
watch(user, (newVal, oldVal) => {
  console.log('user变化了:', newVal)
})

// ✔ 写法3:监听多个数据,用数组包裹
watch([num, ()=>user.name], (newVal, oldVal) => {
  console.log('num或name变化了', newVal)
})

// ✔ 写法4:监听reactive对象的单个属性 + 配置项(核心!)
// immediate:立即执行一次;deep:深度监听
watch(() => user.info.address, (newVal) => {
  console.log('地址变化了', newVal)
}, {
  immediate: true, // 组件初始化时立即执行
  deep: true // 深度监听对象内部属性
})

// ✔ 停止监听:定义变量接收watch返回值,调用即可
const stopWatch = watch(num, ()=>{})
stopWatch() // 停止监听
</script>

✅ 补充:watchEffect 懒人版监听,无需指定监听目标,自动收集依赖,初始化必执行,适合简单场景,按需使用即可。


四、生命周期钩子(Vue3 完整生命周期,无 Options API)

✅ 核心说明

  1. Vue3 生命周期全部是组合式 API 函数,需要手动引入才能使用
  2. 所有生命周期钩子都写在 <script setup>,按执行顺序调用
  3. 没有 beforeCreate / created,这两个钩子的逻辑直接写在 <script setup> 全局即可(组件初始化时最先执行)
  4. 所有钩子都是同步执行,支持异步操作(async/await)

✅ 完整生命周期钩子(按执行顺序,必背)

vue

<script setup>
import { onMounted, onUpdated, onUnmounted, onBeforeMount, onBeforeUpdate, onErrorCaptured } from 'vue'

// 替代 beforeCreate / created → 直接写这里即可
console.log('组件初始化,最先执行')

// 挂载前:DOM还未渲染
onBeforeMount(() => {
  console.log('onBeforeMount:挂载前')
})

// 挂载完成:DOM渲染完毕(最常用!获取DOM/发起请求/初始化数据)✅✅✅
onMounted(() => {
  console.log('onMounted:挂载完成')
  // 在这里发axios请求、初始化echarts、操作DOM,不会报错
})

// 更新前:数据变化,DOM还未更新
onBeforeUpdate(() => {
  console.log('onBeforeUpdate:更新前')
})

// 更新完成:数据变化,DOM更新完毕
onUpdated(() => {
  console.log('onUpdated:更新完成')
})

// 卸载前:组件销毁前执行
onBeforeUnmount(() => {
  console.log('onBeforeUnmount:卸载前')
})

// 卸载完成:组件销毁完毕(常用!清除定时器/取消请求/解绑事件)✅✅✅
onUnmounted(() => {
  console.log('onUnmounted:卸载完成')
  clearInterval(timer) // 清除定时器
})

// 捕获子组件的错误
onErrorCaptured(() => {
  console.log('onErrorCaptured:捕获到错误')
})
</script>

✅ 开发高频使用:onMounted(初始化请求) + onUnmounted(清理副作用),占 90% 的业务场景


五、Vite 项目 核心配置文件 vite.config.js(完整版,可直接复制)

你的项目 vue3-vite-demo 根目录的 vite.config.js 是 Vite 的核心配置文件,所有项目优化、路径别名、跨域代理、打包配置都在这里写,下面是完整版通用配置,包含开发中 99% 的配置项,复制即用,注释清晰!

javascript

运行

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 路径别名:需要安装 npm i @types/node -D 解决路径报错
import path from 'path'

// https://vitejs.dev/config/
export default defineConfig({
  // 1. 插件配置
  plugins: [vue()],

  // 2. 路径别名配置(最常用!简化导入路径,不用写../../)✅
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'), // @ 指向 src目录
      '@components': path.resolve(__dirname, './src/components'),
      '@api': path.resolve(__dirname, './src/api')
    }
  },

  // 3. 开发服务器配置(解决跨域!接口代理,必配)✅✅✅
  server: {
    port: 8080, // 项目启动端口
    open: true, // 启动后自动打开浏览器
    host: '0.0.0.0', // 允许局域网访问
    // 跨域代理:解决前端请求后端接口的跨域问题
    proxy: {
      '/api': {
        target: 'https://localhost:44352', // 你的后端接口地址
        changeOrigin: true, // 开启跨域
        rewrite: (path) => path.replace(/^/api/, '') // 去掉/api前缀
      }
    }
  },

  // 4. 打包配置(优化打包体积、解决中文乱码、指定打包目录)✅
  build: {
    outDir: 'dist', // 打包输出目录
    assetsDir: 'assets', // 静态资源目录
    charset: 'utf-8', // 解决打包后中文乱码
    minify: 'esbuild', // 打包压缩方式,更快更小
    sourcemap: false, // 关闭sourcemap,减小打包体积
    rollupOptions: {
      // 分包配置,优化打包速度
      output: {
        chunkFileNames: 'js/[name]-[hash].js',
        entryFileNames: 'js/[name]-[hash].js',
        assetFileNames: '[ext]/[name]-[hash].[ext]'
      }
    }
  },

  // 5. CSS配置(全局样式、预处理器)
  css: {
    preprocessorOptions: {
      scss: {
        // 全局引入scss变量/混合器,无需在每个组件中import
        additionalData: '@import "@/styles/variable.scss";'
      }
    }
  }
})

六、项目开发 高频实战语法(你之前用到的,补充完整版)

✅ 1. Axios 请求在 Vue3 中的完整写法(你的登录接口,无报错版)

结合你之前的代码,补充 Vue3 + Axios 的标准写法,包含异步、错误捕获、中文不乱码,直接替换你的代码即可

vue

<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'

const token = ref('')
const loading = ref(false)

// 封装登录请求方法
const login = async () => {
  loading.value = true
  try {
    const res = await axios.post(
      'https://localhost:44352/Auth/login', // 去掉重复的?role=system
      { role: 'system', password: '123456' },
      { headers: { 'Content-Type': 'application/json;charset=utf-8' } }
    )
    token.value = res.data.token
    console.log('登录成功,token:', token.value)
  } catch (err) {
    console.log('登录失败:', err)
  } finally {
    loading.value = false
  }
}

// 方式1:点击按钮触发(推荐,业务常用)
// 方式2:组件挂载完成后自动触发
onMounted(() => {
  // login()
})
</script>

<template>
  <button @click="login" :disabled="loading">登录</button>
  <div>token:{{ token }}</div>
</template>

✅ 2. 路由配置(Vue3 + VueRouter4 完整版,项目必配)

vue3-vite-demo 中如果需要路由,安装 npm i vue-router@4,然后在 src/router/index.js 配置,核心写法:

javascript

运行

// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import Login from '@/views/Login.vue'

const routes = [
  { path: '/', redirect: '/home' },
  { path: '/home', component: Home },
  { path: '/login', component: Login }
]

const router = createRouter({
  history: createWebHistory(), // 无#号路由
  routes
})

// 路由守卫:登录拦截
router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token')
  if (to.path !== '/login' && !token) {
    next('/login')
  } else {
    next()
  }
})

export default router

然后在 main.js 引入:

javascript

运行

// main.js
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

七、Vue3 与 Vue2 核心区别(避坑必备,快速记忆)

  1. 语法核心:Vue2 是 Options API(选项式),Vue3 是 Composition API(组合式)+ <script setup> 语法糖
  2. this 关键字:Vue2 处处用 this,Vue3 <script setup>没有 this,所有内容直接调用
  3. 响应式原理:Vue2 是 Object.defineProperty,Vue3 是 Proxy + Reflect,支持数组 / 对象的深度响应式,无需特殊处理
  4. 生命周期:Vue2 是选项式(created/mounted),Vue3 是组合式 API(onMounted/onUnmounted),需要手动引入
  5. 组件通信:Vue2 是 props/emit/refs,Vue3 是 defineProps/defineEmits/defineExpose,更规范
  6. 打包工具:Vue2 是 VueCLI + Webpack,Vue3 推荐 Vite,打包 / 启动速度提升 10 倍 +