一、基础语法知识点
1. 响应式数据 (data)
<template>
<div>
<h1>{{ message }}</h1>
<button @click="updateMessage">更新消息</button>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello, Vue 3!' // 初始化响应式数据
};
},
methods: {
updateMessage() {
this.message = '消息已更新!' // 修改数据触发视图更新
}
}
};
</script>
说明:data 必须是函数,返回包含响应式数据的对象[citation:1]
数据变更自动触发视图更新(基于 Proxy 实现)
2. 方法定义 (methods)
<template>
<div>
<p>计数器: {{ count }}</p>
<button @click="increment">增加</button>
<button @click="decrement">减少</button>
</div>
</template>
<script>
export default {
data() {
return { count: 0 };
},
methods: {
increment() {
this.count++; // 方法中通过 this 访问组件实例
},
decrement() {
this.count--;
}
}
};
</script>
说明
方法通过 this 访问组件属性[citation:1]
事件绑定使用 @click 简写语法
3. 计算属性 (computed)
<template>
<div>
<p>原始价格: {{ price }} 元</p>
<p>折扣价格: {{ discountedPrice }} 元</p>
<button @click="increasePrice">增加价格</button>
</div>
</template>
<script>
export default {
data() {
return { price: 100 };
},
computed: {
discountedPrice() {
return this.price * 0.9; // 自动追踪依赖
}
},
methods: {
increasePrice() {
this.price += 10;
}
}
};
</script>
说明:计算属性基于依赖自动缓存[citation:1]
比方法更高效(重复调用不会重复计算)
4. 侦听器 (watch)
<template>
<div>
<p>用户名: {{ username }}</p>
<input v-model="username" placeholder="输入用户名" />
<p v-if="isUsernameValid">用户名有效</p>
<p v-else>用户名无效</p>
</div>
</template>
<script>
export default {
data() {
return {
username: '',
isUsernameValid: false
};
},
watch: {
username(newVal) {
this.isUsernameValid = newVal.length >= 3; // 深度监听
}
}
};
</script>
说明:监听数据变化执行副作用[citation:1]
支持异步操作和深度监听
5. Props 传递
<!-- ParentComponent.vue -->
<template>
<ChildComponent :greeting="message" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: { ChildComponent },
data() {
return { message: '你好,Vue 3!' };
}
};
</script>
<!-- ChildComponent.vue -->
<template>
<div><h2>{{ greeting }}</h2></div>
</template>
<script>
export default {
props: {
greeting: {
type: String,
required: true // 类型验证
}
}
};
</script>
说明:父传子通过属性绑定[citation:1]
子组件通过 props 选项声明接收
6. 事件通信 (emit)
<!-- 子组件 -->
<template>
<div>
<button @click="notifyParent">通知父组件</button>
</div>
</template>
<script>
export default {
methods: {
notifyParent() {
this.$emit('child-event', '来自子组件的消息'); // 触发自定义事件
}
}
};
</script>
<!-- 父组件 -->
<template>
<div>
<h1>{{ message }}</h1>
<ChildComponent @child-event="handleChildEvent" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: { ChildComponent },
data() {
return { message: '等待子组件的消息...' };
},
methods: {
handleChildEvent(payload) {
this.message = payload; // 处理子组件事件
}
}
};
</script>
说明:子传父通过 $emit 触发事件[citation:1]
事件命名建议使用 kebab-case
7. 双向绑定 (v-model)
<template>
<div>
<input v-model="text" placeholder="输入文本" />
<p>输入的内容: {{ text }}</p>
</div>
</template>
<script>
export default {
data() {
return { text: '' };
}
};
</script>
说明:等价于 :value=”text” @input=”text = $event”[citation:1]
支持修饰符 .lazy/.number/.trim
8. 属性绑定 (v-bind)
<template>
<div>
<img :src="imageUrl" alt="示例图片" />
<button @click="changeImage">更换图片</button>
</div>
</template>
<script>
export default {
data() {
return {
imageUrl: 'https://via.placeholder.com/150',
images: [
'https://via.placeholder.com/150',
'https://via.placeholder.com/200'
]
};
},
methods: {
changeImage() {
const index = Math.floor(Math.random() * this.images.length);
this.imageUrl = this.images[index]; // 动态更新属性
}
}
};
</script>
说明:动态绑定 HTML 属性[citation:1]
简写语法 :src=”imageUrl”
9. 事件绑定 (v-on)
<template>
<div>
<button @click="handleClick($event)">点击事件</button>
</div>
</template>
<script>
export default {
methods: {
handleClick(event) {
console.log('点击事件触发:', event);
}
}
};
</script>
说明:支持事件修饰符 .stop/.prevent/.capture[citation:1]
通过 $event 访问原生事件对象
10. 条件渲染 (v-if/v-else)
<template>
<div>
<p v-if="isLoggedIn">欢迎回来!</p>
<p v-else>请登录</p>
<button @click="toggleLogin">{{ isLoggedIn ? '登出' : '登录' }}</button>
</div>
</template>
<script>
export default {
data() {
return { isLoggedIn: false };
},
methods: {
toggleLogin() {
this.isLoggedIn = !this.isLoggedIn;
}
}
};
</script>
说明:v-if 直接操作 DOM 存在性[citation:1]
适合不频繁切换的场景
11. 列表渲染 (v-for)
<template>
<div>
<h2>水果列表</h2>
<ul>
<li v-for="(fruit, index) in fruits" :key="index">
{{ index + 1 }}. {{ fruit.name }}
<button v-if="fruit.quantity > 0" @click="buyFruit(index)">购买</button>
<span v-else>已售罄</span>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
fruits: [
{ name: '苹果', quantity: 5 },
{ name: '香蕉', quantity: 0 }
]
};
},
methods: {
buyFruit(index) {
if (this.fruits[index].quantity > 0) {
this.fruits[index].quantity--;
}
}
}
};
</script>
说明:遍历数组/对象生成列表[citation:1]
必须提供 :key 提高渲染效率
二、组件系统
1. 组件注册
<!-- 全局注册 -->
<script>
import { createApp } from 'vue';
import App from './App.vue';
import MyComponent from './components/MyComponent.vue';
const app = createApp(App);
app.component('MyComponent', MyComponent); // 全局注册
app.mount('#app');
</script>
<!-- 局部注册 -->
<script>
import MyComponent from './components/MyComponent.vue';
export default {
components: {
MyComponent // 局部注册
}
};
</script>
说明:
全局注册使用 app.component()[citation:4]
局部注册在组件的 components 选项中声明
2. Props 验证
export default {
props: {
// 基础类型检查
propA: Number,
// 多个类型
propB: [String, Number],
// 必填字符串
propC: {
type: String,
required: true
},
// 默认值
propD: {
type: Number,
default: 100
},
// 自定义验证
propE: {
validator(value) {
return ['success', 'warning'].includes(value);
}
}
}
};
说明:支持类型检查、必填、默认值[citation:4]
复杂验证使用 validator 函数
3. Slots 插槽
<!-- 子组件 -->
<template>
<div class="card">
<slot name="header"></slot>
<slot></slot> <!-- 默认插槽 -->
<slot name="footer"></slot>
</div>
</template>
<!-- 父组件 -->
<template>
<MyComponent>
<template #header><h2>标题</h2></template>
<p>内容部分</p>
<template #footer><button>确定</button></template>
</MyComponent>
</template>
说明:通过 name 属性定义具名插槽[citation:4]
作用域插槽通过 v-slot 传递数据
4. 生命周期钩子
import { onMounted, onUpdated, onUnmounted } from 'vue';
export default {
setup() {
onMounted(() => {
console.log('组件挂载完成');
});
onUpdated(() => {
console.log('组件更新');
});
onUnmounted(() => {
console.log('组件卸载');
});
}
};
说明:Composition API 生命周期钩子[citation:16]
对应 Options API 的 mounted/updated/beforeUnmount
三、组合式 API
1. setup 函数
<template>
<div>{{ count }}</div>
<button @click="increment">+1</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0); // 响应式引用
function increment() {
count.value++; // 修改值
}
</script>
说明:组合式 API 入口[citation:16]
setup 语法糖自动暴露变量和方法
2. 响应式系统
import { ref, reactive } from 'vue';
const count = ref(0); // 基本类型响应式
const state = reactive({ // 对象响应式
name: '张三',
age: 20
});
说明:ref 包装基本类型[citation:16]
reactive 处理对象/数组
3. 高级响应式 API
const doubleCount = computed(() => count.value * 2); // 计算属性
watch(count, (newVal) => {
console.log('count 变化:', newVal); // 侦听器
});
watchEffect(() => {
console.log('自动追踪依赖:', state.name); // 自动收集依赖
});
说明:computed 创建计算属性[citation:16]
watch/watchEffect 实现副作用
四、高级特性
1. 混入 (Mixin)
// loggerMixin.js
export const loggerMixin = {
created() {
console.log(`组件 ${this.$options.name} 创建`);
},
methods: {
log(msg) {
console.log(`[${this.$options.name}] ${msg}`);
}
}
};
// 使用混入
export default {
mixins: [loggerMixin],
created() {
this.log('初始化完成');
}
};
说明:
提取公共逻辑[citation:17]
合并策略:组件选项覆盖混入
2. Teleport
<template>
<button @click="showModal = true">打开弹窗</button>
<Teleport to="body"> <!-- 渲染到 body -->
<div v-if="showModal" class="modal">
<h3>弹窗内容</h3>
<button @click="showModal = false">关闭</button>
</div>
</Teleport>
</template>
说明:
将内容渲染到 DOM 任意位置[citation:13]
适合实现全局弹窗
3. Suspense
<template>
<Suspense>
<template #default>
<AsyncComponent /> <!-- 异步组件 -->
</template>
<template #fallback>
<div>加载中...</div>
</template>
</Suspense>
</template>
说明:
处理异步依赖[citation:13]
显示加载状态直到内容就绪