Vue.js 中文教程
1. 项目概述
Vue.js 是一个渐进式 JavaScript 框架,用于构建用户界面。它的设计理念是通过简单的 API 实现响应式数据绑定和组件化开发,使得构建复杂的单页应用变得更加简单和可维护。
1.1 主要功能
- 响应式数据绑定:自动追踪依赖并更新 DOM
- 组件化开发:将 UI 拆分为独立、可复用的组件
- 虚拟 DOM:通过虚拟 DOM 提高渲染性能
- 指令系统:提供丰富的指令来操作 DOM
- 过渡动画:内置的过渡效果系统
- 计算属性:缓存计算结果,提高性能
- 监听器:响应数据变化
- 生命周期钩子:在组件不同阶段执行代码
- 模板语法:简洁直观的模板语法
- 插件系统:可扩展的插件机制
1.2 技术栈特点
- 易于学习:API 设计简洁明了,学习曲线平缓
- 灵活渐进:可以从简单的库开始,逐步扩展为完整的框架
- 性能优异:响应式系统和虚拟 DOM 保证了高效的渲染
- 文档完善:官方文档详尽,示例丰富
- 生态系统丰富:拥有大量的第三方库和工具
- TypeScript 支持:官方支持 TypeScript
- 强大的社区支持:作为前端开发的主流框架之一,拥有庞大的社区和丰富的学习资源
1.3 GitHub Stars
200k+
2. 安装设置
2.1 使用 npm 或 yarn
# 使用 npm
npm install vue
# 使用 yarn
yarn add vue2.2 使用 CDN
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>2.3 使用 Vue CLI
Vue CLI 是 Vue 官方推荐的项目脚手架工具,它会自动配置好开发环境,让你可以专注于编写代码。
# 安装 Vue CLI
npm install -g @vue/cli
# 创建新的 Vue 项目
vue create my-app
# 进入项目目录
cd my-app
# 启动开发服务器
npm run serve2.4 使用 Vite
Vite 是一个现代化的前端构建工具,它提供了更快的开发体验。
# 使用 npm
npm create vite@latest my-app -- --template vue
# 使用 yarn
yarn create vite my-app --template vue
# 使用 pnpm
pnpm create vite my-app --template vue
# 进入项目目录
cd my-app
# 安装依赖
npm install
# 启动开发服务器
npm run dev3. 基本使用
3.1 创建 Vue 实例
// 引入 Vue
import Vue from 'vue'
// 创建 Vue 实例
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})<!-- HTML 模板 -->
<div id="app">
{{ message }}
</div>3.2 模板语法
3.2.1 文本插值
<div>{{ message }}</div>3.2.2 指令
<!-- v-bind 指令:绑定属性 -->
<div v-bind:class="className"></div>
<!-- 简写 -->
<div :class="className"></div>
<!-- v-on 指令:绑定事件 -->
<button v-on:click="handleClick">Click me</button>
<!-- 简写 -->
<button @click="handleClick">Click me</button>
<!-- v-if 指令:条件渲染 -->
<div v-if="isVisible">Visible</div>
<!-- v-for 指令:列表渲染 -->
<ul>
<li v-for="item in items" :key="item.id">
{{ item.text }}
</li>
</ul>
<!-- v-model 指令:双向数据绑定 -->
<input v-model="message" type="text">3.3 计算属性和监听器
3.3.1 计算属性
new Vue({
el: '#app',
data: {
firstName: 'John',
lastName: 'Doe'
},
computed: {
// 计算属性的 getter
fullName: function () {
// `this` 指向 vm 实例
return this.firstName + ' ' + this.lastName
}
}
})3.3.2 监听器
new Vue({
el: '#app',
data: {
message: 'Hello',
watchCount: 0
},
watch: {
// 当 message 变化时执行
message: function (newValue, oldValue) {
this.watchCount++
console.log('message changed from', oldValue, 'to', newValue)
}
}
})3.4 方法
new Vue({
el: '#app',
data: {
count: 0
},
methods: {
increment: function () {
this.count++
}
}
})3.5 生命周期钩子
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
beforeCreate: function () {
console.log('beforeCreate')
},
created: function () {
console.log('created')
},
beforeMount: function () {
console.log('beforeMount')
},
mounted: function () {
console.log('mounted')
},
beforeUpdate: function () {
console.log('beforeUpdate')
},
updated: function () {
console.log('updated')
},
beforeDestroy: function () {
console.log('beforeDestroy')
},
destroyed: function () {
console.log('destroyed')
}
})4. 组件化开发
4.1 注册组件
4.1.1 全局注册
// 注册全局组件
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})4.1.2 局部注册
// 定义组件
const MyComponent = {
template: '<div>A custom component!</div>'
}
// 在 Vue 实例中注册局部组件
new Vue({
el: '#app',
components: {
'my-component': MyComponent
}
})4.2 组件通信
4.2.1 Props 向下传递
// 父组件
const ParentComponent = {
template: '<child-component :message="parentMessage"></child-component>',
data() {
return {
parentMessage: 'Hello from parent'
}
}
}
// 子组件
const ChildComponent = {
props: ['message'],
template: '<div>{{ message }}</div>'
}4.2.2 事件向上传递
// 子组件
const ChildComponent = {
template: '<button @click="$emit(\'child-click\', \'Hello from child\')">Click me</button>'
}
// 父组件
const ParentComponent = {
template: '<child-component @child-click="handleChildClick"></child-component>',
methods: {
handleChildClick: function (message) {
console.log(message) // 输出: Hello from child
}
}
}4.2.3 插槽
// 子组件
const ChildComponent = {
template: '<div><slot></slot></div>'
}
// 父组件
const ParentComponent = {
template: '<child-component>Content from parent</child-component>'
}5. 高级功能
5.1 自定义指令
// 注册全局自定义指令
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时...
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
// 在模板中使用
<input v-focus>5.2 过滤器
// 注册全局过滤器
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
// 在模板中使用
<div>{{ message | capitalize }}</div>5.3 混入
// 定义混入对象
const myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// 使用混入
new Vue({
mixins: [myMixin]
})5.4 插件
// 定义插件
const MyPlugin = {
install(Vue, options) {
// 添加全局方法或属性
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 添加全局资源
Vue.directive('my-directive', {
bind(el, binding, vnode, oldVnode) {
// 逻辑...
}
})
// 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
})
// 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
}
// 使用插件
Vue.use(MyPlugin)5.5 过渡动画
<!-- 单个元素的过渡 -->
<transition name="fade">
<div v-if="show">Hello</div>
</transition>
<!-- 列表的过渡 -->
<transition-group name="list" tag="ul">
<li v-for="item in items" :key="item.id">
{{ item.text }}
</li>
</transition-group>/* 淡入淡出效果 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-to
/* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
/* 列表过渡效果 */
.list-enter-active,
.list-leave-active {
transition: all 0.5s;
}
.list-enter,
.list-leave-to
/* .list-leave-active below version 2.1.8 */ {
opacity: 0;
transform: translateX(30px);
}5.6 响应式原理
Vue 的响应式系统基于 Object.defineProperty() 方法,它会遍历 data 对象的所有属性,并使用 Object.defineProperty() 将这些属性转换为 getter/setter。当属性被访问或修改时,Vue 会追踪依赖并触发更新。
// 简化版的响应式原理
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
console.log('get value')
return val
},
set: function reactiveSetter(newVal) {
if (newVal === val) return
console.log('set value:', newVal)
val = newVal
}
})
}
const obj = {}
defineReactive(obj, 'name', 'Vue')
console.log(obj.name) // 输出: get value, Vue
obj.name = 'React' // 输出: set value: React6. Vue 3 新特性
6.1 Composition API
Composition API 是 Vue 3 中引入的新 API,它提供了一种新的组织组件逻辑的方式,使得代码更加可维护和可复用。
import { ref, computed, onMounted } from 'vue'
export default {
setup() {
// 响应式数据
const count = ref(0)
// 计算属性
const doubleCount = computed(() => count.value * 2)
// 方法
const increment = () => {
count.value++
}
// 生命周期钩子
onMounted(() => {
console.log('Component mounted')
})
// 返回暴露给模板的内容
return {
count,
doubleCount,
increment
}
}
}6.2 Teleport
Teleport 允许你将组件的内容渲染到 DOM 中的任何位置,而不仅仅是组件的父级元素内。
import { ref } from 'vue'
export default {
setup() {
const showModal = ref(false)
return {
showModal
}
}
}<template>
<button @click="showModal = true">Show Modal</button>
<teleport to="body">
<div v-if="showModal" class="modal">
<div class="modal-content">
<h2>Modal</h2>
<p>Modal content</p>
<button @click="showModal = false">Close</button>
</div>
</div>
</teleport>
</template>6.3 Fragments
Vue 3 允许组件返回多个根节点,而不需要用一个额外的 div 包裹。
export default {
template: `
<div>First root</div>
<div>Second root</div>
`
}6.4 其他新特性
- 更好的 TypeScript 支持:Vue 3 是用 TypeScript 重写的,提供了更好的类型推断
- Suspense:用于处理异步组件的加载状态
- Vue Router 4:与 Vue 3 兼容的路由库
- Pinia:Vue 3 的官方状态管理库,替代 Vuex
- Vite:Vue 3 官方推荐的构建工具
7. 实际应用场景
7.1 表单处理
new Vue({
el: '#app',
data: {
form: {
username: '',
password: ''
}
},
methods: {
submitForm: function () {
console.log('Form submitted:', this.form)
// 处理表单提交逻辑
}
}
})<form @submit.prevent="submitForm">
<div>
<label>Username:</label>
<input v-model="form.username" type="text">
</div>
<div>
<label>Password:</label>
<input v-model="form.password" type="password">
</div>
<button type="submit">Submit</button>
</form>7.2 数据获取
new Vue({
el: '#app',
data: {
users: [],
loading: true,
error: null
},
mounted: function () {
this.fetchUsers()
},
methods: {
fetchUsers: function () {
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(data => {
this.users = data
this.loading = false
})
.catch(error => {
this.error = error.message
this.loading = false
})
}
}
})<div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error }}</div>
<ul v-else>
<li v-for="user in users" :key="user.id">
{{ user.name }} ({{ user.email }})
</li>
</ul>7.3 路由
使用 Vue Router 来处理应用的路由。
# 安装 Vue Router
npm install vue-router// 引入 Vue 和 Vue Router
import Vue from 'vue'
import VueRouter from 'vue-router'
// 注册 Vue Router
Vue.use(VueRouter)
// 定义路由组件
const Home = {
template: '<div>Home</div>'
}
const About = {
template: '<div>About</div>'
}
// 创建路由实例
const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
})
// 创建 Vue 实例并挂载路由
new Vue({
el: '#app',
router
})<div id="app">
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<router-view></router-view>
</div>7.4 状态管理
使用 Vuex 来管理应用的状态。
# 安装 Vuex
npm install vuex// 引入 Vue 和 Vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 注册 Vuex
Vue.use(Vuex)
// 创建 store
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
},
getters: {
doubleCount: state => state.count * 2
}
})
// 创建 Vue 实例并挂载 store
new Vue({
el: '#app',
store,
computed: {
count() {
return this.$store.state.count
},
doubleCount() {
return this.$store.getters.doubleCount
}
},
methods: {
increment() {
this.$store.commit('increment')
},
incrementAsync() {
this.$store.dispatch('incrementAsync')
}
}
})<div id="app">
<p>Count: {{ count }}</p>
<p>Double Count: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
<button @click="incrementAsync">Increment Async</button>
</div>8. 代码优化建议
8.1 使用计算属性而非方法
对于需要基于响应式数据计算的值,使用计算属性而不是方法,因为计算属性会缓存结果,只有当依赖变化时才会重新计算。
// 推荐
computed: {
fullName() {
return this.firstName + ' ' + this.lastName
}
}
// 不推荐
methods: {
getFullName() {
return this.firstName + ' ' + this.lastName
}
}8.2 合理使用 v-if 和 v-show
对于频繁切换的元素,使用 v-show 而不是 v-if,因为 v-show 只是切换元素的 display 属性,而 v-if 会销毁和重建元素。
<!-- 频繁切换时使用 -->
<div v-show="isVisible">Visible</div>
<!-- 不频繁切换时使用 -->
<div v-if="isVisible">Visible</div>8.3 使用 key 属性
在使用 v-for 渲染列表时,总是添加 key 属性,并且使用唯一且稳定的值作为 key,避免使用索引作为 key(除非列表是静态的)。
<!-- 推荐 -->
<li v-for="item in items" :key="item.id">{{ item.text }}</li>
<!-- 不推荐 -->
<li v-for="(item, index) in items" :key="index">{{ item.text }}</li>8.4 避免在模板中使用复杂表达式
对于复杂的表达式,将其移到计算属性或方法中。
// 推荐
computed: {
isEligible() {
return this.age >= 18 && this.hasPermission
}
}
// 在模板中使用
<div v-if="isEligible">Eligible</div>
// 不推荐
<div v-if="age >= 18 && hasPermission">Eligible</div>8.5 使用防抖和节流
对于频繁触发的事件,如输入、滚动等,使用防抖或节流来优化性能。
// 防抖
methods: {
search: _.debounce(function (query) {
// 搜索逻辑
}, 300)
}
// 节流
methods: {
handleScroll: _.throttle(function () {
// 滚动逻辑
}, 100)
}8.6 合理使用 watch
对于需要响应数据变化执行副作用的场景,使用 watch。但要注意,对于复杂的计算,优先使用计算属性。
watch: {
// 监听单个属性
message(newValue, oldValue) {
// 执行副作用
},
// 监听对象的所有属性
user: {
handler(newValue, oldValue) {
// 执行副作用
},
deep: true
}
}8.7 组件拆分
将大型组件拆分为更小、更专注的组件,提高代码的可维护性和可测试性。
8.8 使用 TypeScript
对于大型应用,使用 TypeScript 来提高代码的可维护性和类型安全性。
8.9 优化首屏加载速度
- 代码分割:使用动态导入来分割代码
- 懒加载:懒加载非关键资源
- 缓存:合理使用缓存策略
- 压缩:压缩 JavaScript、CSS 和 HTML 文件
8.10 合理使用 Vuex
对于复杂的状态管理,使用 Vuex。但对于简单的应用,使用组件的状态即可,避免过度使用 Vuex。
9. 参考资源
10. 总结
Vue.js 是一个功能强大、灵活且高效的前端框架,它通过响应式数据绑定、组件化开发、虚拟 DOM 等特性,使得构建复杂的单页应用变得更加简单和可维护。
通过本教程的学习,你应该已经掌握了 Vue.js 的核心概念和基本使用方法,包括响应式数据绑定、组件化开发、指令系统、计算属性、监听器、生命周期钩子等。同时,你也了解了 Vue.js 的一些高级特性,如自定义指令、过滤器、混入、插件、过渡动画等。
Vue.js 的生态系统非常丰富,有许多优秀的第三方库和工具,如 Vue Router、Vuex、Element UI、Ant Design Vue 等,它们可以帮助你更高效地开发 Vue.js 应用。
作为前端开发的主流框架之一,Vue.js 拥有庞大的社区和丰富的学习资源,如果你在学习或开发过程中遇到问题,可以通过官方文档、社区论坛、GitHub 等渠道寻求帮助。
Vue 3 的发布带来了许多新特性,如 Composition API、Teleport、Fragments 等,这些新特性进一步提升了 Vue.js 的开发体验和性能。
希望本教程对你有所帮助,祝你在 Vue.js 开发之路上取得成功!