一、Vue 核心概念
1. Vue 是什么
// Vue 是一个渐进式 JavaScript 框架
// 特点:易用、灵活、高效
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
2. MVVM 模式
Model(数据) ↔ ViewModel(Vue实例) ↔ View(DOM)
双向数据绑定
二、Vue 实例
1. 创建 Vue 实例
const vm = new Vue({
// 选项对象
el: '#app', // 挂载元素
data: { // 数据
message: 'Hello'
},
methods: { // 方法
greet() {
alert(this.message);
}
},
computed: { // 计算属性
reversedMessage() {
return this.message.split('').reverse().join('');
}
},
watch: { // 侦听器
message(newVal, oldVal) {
console.log('消息变化了', oldVal, '→', newVal);
}
}
});
2. 生命周期钩子
export default {
// 初始化阶段
beforeCreate() {
// 实例初始化之后,数据观测之前
},
created() {
// 实例创建完成,可以访问 data、methods
// 适合发起异步请求
},
// 挂载阶段
beforeMount() {
// 模板编译/挂载之前
},
mounted() {
// 挂载完成,可以访问 DOM
// 适合操作 DOM、初始化插件
},
// 更新阶段
beforeUpdate() {
// 数据更新,DOM 重新渲染之前
},
updated() {
// DOM 更新完成
},
// 销毁阶段
beforeDestroy() {
// 实例销毁之前
// 适合清理定时器、解绑事件
},
destroyed() {
// 实例销毁后
},
// keep-alive 相关(仅 keep-alive 组件)
activated() {
// 组件激活时
},
deactivated() {
// 组件停用时
}
}
三、模板语法
1. 插值
<template>
<!-- 文本插值 -->
<p>{{ message }}</p>
<!-- 原始 HTML -->
<p v-html="rawHtml"></p>
<!-- 属性绑定 -->
<div :id="dynamicId"></div>
<button :disabled="isDisabled">按钮</button>
<!-- JavaScript 表达式 -->
<p>{{ number + 1 }}</p>
<p>{{ ok ? 'YES' : 'NO' }}</p>
<p>{{ message.split('').reverse().join('') }}</p>
</template>
2. 指令
<template>
<!-- 条件渲染 -->
<p v-if="type === 'A'">A</p>
<p v-else-if="type === 'B'">B</p>
<p v-else>C</p>
<!-- v-show 通过 CSS display 控制 -->
<p v-show="isShow">显示/隐藏</p>
<!-- 列表渲染 -->
<ul>
<li v-for="(item, index) in items" :key="item.id">
{{ index }} - {{ item.name }}
</li>
</ul>
<!-- 遍历对象 -->
<div v-for="(value, key) in object">
{{ key }}: {{ value }}
</div>
<!-- 事件处理 -->
<button @click="handleClick">点击</button>
<button @click="handleClick($event, 'param')">带参数</button>
<!-- 事件修饰符 -->
<form @submit.prevent="onSubmit"></form>
<a @click.stop="doThis"></a>
<input @keyup.enter="submit">
<!-- 双向绑定 -->
<input v-model="message" type="text">
<textarea v-model="message"></textarea>
<input v-model="checked" type="checkbox">
<input v-model="picked" type="radio" value="A">
<select v-model="selected">
<option>A</option>
<option>B</option>
</select>
</template>
四、计算属性和侦听器
1. 计算属性 (computed)
export default {
data() {
return {
firstName: '张',
lastName: '三',
books: [
{ title: 'Vue指南', price: 50 },
{ title: 'React指南', price: 60 }
]
};
},
computed: {
// 基本用法
fullName() {
return this.firstName + this.lastName;
},
// 带 setter 的计算属性
fullName2: {
get() {
return this.firstName + ' ' + this.lastName;
},
set(newValue) {
const names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[1];
}
},
// 依赖数组的计算属性
totalPrice() {
return this.books.reduce((sum, book) => sum + book.price, 0);
}
}
};
2. 侦听器 (watch)
export default {
data() {
return {
question: '',
answer: '',
user: {
name: '张三',
info: {
age: 20
}
}
};
},
watch: {
// 基本用法
question(newVal, oldVal) {
this.getAnswer();
},
// 深度监听对象
user: {
handler(newVal, oldVal) {
console.log('user 变化了');
},
deep: true, // 深度监听
immediate: true // 立即执行
},
// 监听对象某个属性
'user.info.age': function(newVal, oldVal) {
console.log('age 变化了');
}
},
methods: {
getAnswer() {
// 异步操作
setTimeout(() => {
this.answer = '答案是...';
}, 1000);
}
}
};
五、Class 与 Style 绑定
<template>
<!-- Class 绑定 -->
<div :class="{ active: isActive, 'text-danger': hasError }"></div>
<div :class="[activeClass, errorClass]"></div>
<div :class="[isActive ? activeClass : '', errorClass]"></div>
<!-- Style 绑定 -->
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<div :style="[baseStyles, overridingStyles]"></div>
<!-- 自动添加前缀,支持数组/对象 -->
<div :style="{ transform: 'scale(' + scale + ')' }"></div>
</template>
<script>
export default {
data() {
return {
isActive: true,
hasError: false,
activeClass: 'active',
errorClass: 'text-danger',
activeColor: 'red',
fontSize: 14,
baseStyles: { color: 'red' },
overridingStyles: { fontSize: '20px' },
scale: 1.2
};
}
};
</script>
六、组件基础
1. 组件注册
// 全局注册
Vue.component('my-component', {
template: '<div>我的组件</div>'
});
// 局部注册
const ComponentA = {
template: '<div>组件A</div>'
};
export default {
components: {
'component-a': ComponentA
}
};
2. Props 传递数据
<!-- 父组件 -->
<template>
<child-component :title="parentTitle" @custom-event="handleEvent" />
</template>
<script>
export default {
data() {
return {
parentTitle: '来自父组件的标题'
};
},
methods: {
handleEvent(data) {
console.log('收到子组件事件:', data);
}
}
};
</script>
<!-- 子组件 ChildComponent.vue -->
<template>
<div>
<h3>{{ title }}</h3>
<button @click="$emit('custom-event', '数据')">触发事件</button>
</div>
</template>
<script>
export default {
props: {
// 基础类型检查
title: String,
// 多个可能的类型
propA: [String, Number],
// 必填项
propB: {
type: String,
required: true
},
// 默认值
propC: {
type: Number,
default: 100
},
// 自定义验证函数
propD: {
validator(value) {
return ['success', 'warning', 'danger'].includes(value);
}
}
},
methods: {
emitEvent() {
this.$emit('custom-event', '自定义数据');
}
}
};
</script>
3. 插槽 Slot
<!-- 子组件 -->
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot>默认内容</slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<!-- 父组件使用 -->
<template>
<child-component>
<template v-slot:header>
<h1>标题</h1>
</template>
<p>主要内容</p>
<template #footer>
<p>底部信息</p>
</template>
</child-component>
</template>
4. 作用域插槽
<!-- 子组件 -->
<template>
<ul>
<li v-for="item in items">
<slot :item="item">
{{ item.name }}
</slot>
</li>
</ul>
</template>
<!-- 父组件使用 -->
<template>
<my-list :items="userList">
<template v-slot:default="slotProps">
<span class="red">{{ slotProps.item.name }}</span>
</template>
</my-list>
</template>
七、组件通信
1. 父子组件通信
// 父 → 子:props
// 子 → 父:$emit
// 父组件访问子组件
this.$refs.childName.methodName();
// 子组件访问父组件
this.$parent.methodName();
// 访问根实例
this.$root.methodName();
2. 事件总线(非父子组件)
// eventBus.js
import Vue from 'vue';
export const EventBus = new Vue();
// 组件A发送事件
EventBus.$emit('event-name', data);
// 组件B接收事件
EventBus.$on('event-name', (data) => {
console.log(data);
});
// 取消监听
EventBus.$off('event-name');
3. Provide / Inject(跨级组件)
// 祖先组件
export default {
provide() {
return {
theme: this.theme,
changeTheme: this.changeTheme
};
},
data() {
return {
theme: 'dark'
};
},
methods: {
changeTheme(theme) {
this.theme = theme;
}
}
};
// 后代组件
export default {
inject: ['theme', 'changeTheme'],
mounted() {
console.log(this.theme);
this.changeTheme('light');
}
};
八、表单输入绑定修饰符
<template>
<!-- .lazy - 转为 change 事件后同步 -->
<input v-model.lazy="msg">
<!-- .number - 自动转为数字 -->
<input v-model.number="age" type="number">
<!-- .trim - 自动过滤首尾空白 -->
<input v-model.trim="msg">
<!-- 组合使用 -->
<input v-model.lazy.trim="msg">
</template>
九、Vue 实例属性/方法
// 常用实例属性
this.$data // 数据对象
this.$props // props 对象
this.$el // 根 DOM 元素
this.$options // 实例选项
this.$parent // 父实例
this.$root // 根实例
this.$children // 子实例数组
this.$slots // 插槽内容
this.$scopedSlots // 作用域插槽
this.$refs // 持有注册过 ref 的所有 DOM/组件
this.$attrs // 父作用域中不作为 prop 被识别的 attribute
this.$listeners // 父作用域中的事件监听器
// 常用实例方法
this.$watch() // 创建侦听器
this.$set() // 响应式添加属性
this.$delete() // 响应式删除属性
this.$on() // 监听自定义事件
this.$once() // 监听一次性事件
this.$off() // 取消事件监听
this.$emit() // 触发事件
this.$nextTick() // DOM 更新后执行回调
this.$forceUpdate() // 强制重新渲染
十、最佳实践
1. 组件设计原则
- • 单一职责
- • 可复用性
- • 可维护性
- • 良好的命名规范
2. 性能优化
// 1. 合理使用 v-if 和 v-show
// 频繁切换用 v-show,不常变化用 v-if
// 2. 列表使用 key
<li v-for="item in list" :key="item.id">
// 3. 避免同时使用 v-for 和 v-if
// 错误写法
<div v-for="item in list" v-if="item.active">
// 正确写法
<div v-for="item in activeList">
// 4. 合理使用计算属性和侦听器
// 计算属性缓存结果,避免重复计算
// 5. 组件懒加载
const LazyComponent = () => import('./LazyComponent.vue');
3. 代码规范
// 组件文件名:PascalCase(如 MyComponent.vue)
// 组件名:PascalCase(如 MyComponent)
// Prop 定义:提供类型和默认值
// 事件名:kebab-case(如 custom-event)
十一、常见问题
1. 数组/对象更新检测
// Vue 不能检测到以下数组变动
// 解决方案:
this.$set(this.items, index, newValue);
this.items.splice(index, 1, newValue);
// 添加新属性到对象
this.$set(this.obj, 'newProp', 123);
2. nextTick 的使用
// DOM 更新后执行
this.message = '更新';
this.$nextTick(() => {
// DOM 现在更新了
console.log(this.$el.textContent);
});
3. 组件命名冲突
<!-- 使用 kebab-case -->
<my-component-name></my-component-name>
<!-- 或 PascalCase -->
<MyComponentName></MyComponentName>
这个基础知识涵盖了 Vue 2.x 的核心内容,掌握了这些就能进行基本的 Vue 开发了。