從零學習Vue.js 目錄 引言 準備工作 Vue.js 基礎 3.1 Vue 實例 3.2 模板語法 3.3 數據綁定 3.4 計算屬性和偵聽器 3.5 Class 與 Style 綁定 3.6 條件渲染 3.7 列表渲染 3.8 事件處理 3.9 表單輸入綁定 Vue.js 組件 4.1 組件基 ...
從零學習Vue.js
目錄
- 引言
- 準備工作
- Vue.js 基礎
- 3.1 Vue 實例
- 3.2 模板語法
- 3.3 數據綁定
- 3.4 計算屬性和偵聽器
- 3.5 Class 與 Style 綁定
- 3.6 條件渲染
- 3.7 列表渲染
- 3.8 事件處理
- 3.9 表單輸入綁定
- Vue.js 組件
- 4.1 組件基礎
- 4.2 組件註冊
- 4.3 父子組件通信
- 4.4 插槽
- 4.5 動態組件
- 4.6 非同步組件
- Vue Router
- 5.1 路由基礎
- 5.2 動態路由匹配
- 5.3 嵌套路由
- 5.4 路由守衛
- 5.5 路由元信息
- 5.6 導航守衛
- 5.7 路由懶載入
- Vuex 狀態管理
- 6.1 Vuex 基礎
- 6.2 核心概念
- 6.3 模塊化
- 6.4 中間件
- 6.5 輔助函數
- 項目實戰
- 7.1 項目初始化
- 7.2 組件設計
- 7.3 路由配置
- 7.4 狀態管理
- 7.5 API 集成
- 7.6 部署與優化
- 進階概念
- 8.1 自定義指令
- 8.2 混入
- 8.3 插件
- 8.4 服務端渲染 (SSR)
- 8.5 Vue 3 新特性
- 總結與展望
1. 引言
Vue.js 是一個用於構建用戶界面的漸進式 JavaScript 框架。它的設計理念是儘量簡單,同時提供足夠的靈活性和性能來應對複雜的應用需求。本書將帶你從零開始學習 Vue.js,逐步掌握其核心概念和高級特性。
2. 準備工作
在開始學習 Vue.js 之前,你需要具備以下基礎知識:
- HTML/CSS 基礎
- JavaScript 基礎
此外,你需要準備以下開發工具:
- 一個現代瀏覽器(如 Chrome 或 Firefox)
- 一個代碼編輯器(如 VS Code 或 Sublime Text)
- Node.js 和 npm(用於管理項目依賴)
安裝 Node.js 和 npm:
- 訪問 Node.js 官網 下載並安裝適用於你操作系統的版本。
- 安裝完成後,打開終端(或命令提示符)並運行以下命令,確認安裝成功:
node -v npm -v
3. Vue.js 基礎
3.1 Vue 實例
Vue.js 應用的核心是 Vue 實例。你可以通過創建一個新的 Vue 實例來啟動一個 Vue 應用。
<!DOCTYPE html>
<html>
<head>
<title>Vue.js 學習</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">{{ message }}</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
</script>
</body>
</html>
3.2 模板語法
Vue.js 使用一種基於 HTML 的模板語法,允許你聲明式地綁定數據到 DOM。
<div id="app">
<p>{{ message }}</p>
<p v-bind:title="message">滑鼠懸停查看消息</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
</script>
3.3 數據綁定
Vue.js 提供了兩種主要的數據綁定方式:插值和指令。
<div id="app">
<p>{{ message }}</p>
<input v-model="message">
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
</script>
3.4 計算屬性和偵聽器
計算屬性用於對數據進行計算和處理,而偵聽器用於監聽數據的變化。
<div id="app">
<p>原始消息: {{ message }}</p>
<p>反轉消息: {{ reversedMessage }}</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
computed: {
reversedMessage: function () {
return this.message.split('').reverse().join('');
}
}
});
</script>
3.5 Class 與 Style 綁定
你可以動態地綁定 HTML 元素的 class 和 style。
<div id="app">
<div v-bind:class="{ active: isActive }">Class 綁定</div>
<div v-bind:style="styleObject">Style 綁定</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
isActive: true,
styleObject: {
color: 'red',
fontSize: '20px'
}
}
});
</script>
3.6 條件渲染
使用 v-if
指令可以根據條件渲染元素。
<div id="app">
<p v-if="seen">現在你看到我了</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
seen: true
}
});
</script>
3.7 列表渲染
使用 v-for
指令可以渲染一個列表。
<div id="app">
<ul>
<li v-for="item in items" v-bind:key="item.id">
{{ item.text }}
</li>
</ul>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
items: [
{ id: 1, text: '蘋果' },
{ id: 2, text: '香蕉' },
{ id: 3, text: '橙子' }
]
}
});
</script>
3.8 事件處理
使用 v-on
指令可以監聽 DOM 事件。
<div id="app">
<button v-on:click="greet">點擊我</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
methods: {
greet: function () {
alert(this.message);
}
}
});
</script>
3.9 表單輸入綁定
使用 v-model
指令可以實現表單輸入與應用狀態的雙向綁定。
<div id="app">
<input v-model="message">
<p>{{ message }}</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
</script>
4. Vue.js 組件
4.1 組件基礎
組件是 Vue.js 的核心概念,用於構建可復用的 UI 片段。
<div id="app">
<my-component></my-component>
</div>
<script>
Vue.component('my-component', {
template: '<p>這是一個組件</p>'
});
var app = new Vue({
el: '#app'
});
</script>
4.2 組件註冊
組件可以全局註冊或局部註冊。
<!-- 全局註冊 -->
<script>
Vue.component('my-component', {
template: '<p>這是一個全局註冊的組件</p>'
});
</script>
<!-- 局部註冊 -->
<script>
var Child = {
template: '<p>這是一個局部註冊的組件</p>'
};
var app = new Vue({
el: '#app',
components: {
'my-component': Child
}
});
</script>
4.3 父子組件通信
父組件可以通過 props 向子組件傳遞數據,子組件可以通過事件向父組件發送消息。
<div id="app">
<child-component v-bind:message="parentMessage"></child-component>
</div>
<script>
Vue.component('child-component', {
props: ['message'],
template: '<p>{{ message }}</p>'
});
var app = new Vue({
el: '#app',
data: {
parentMessage: '來自父組件的消息'
}
});
</script>
4.4 插槽
插槽允許你在組件中插入內容。
<div id="app">
<alert-box>
<strong>註意!</strong> 這是一個重要的消息。
</alert-box>
</div>
<script>
Vue.component('alert-box', {
template: `
<div class="alert-box">
<slot></slot>
</div>
`
});
var app = new Vue({
el: '#app'
});
</script>
4.5 動態組件
動態組件允許你在同一個掛載點動態切換多個組件。
<div id="app">
<component v-bind:is="currentComponent"></component>
<button v-on:click="currentComponent = 'component-a'">顯示 A</button>
<button v-on:click="currentComponent = 'component-b'">顯示 B</button>
</div>
<script>
Vue.component('component-a', {
template: '<p>組件 A</p>'
});
Vue.component('component-b', {
template: '<p>組件 B</p>'
});
var app = new Vue({
el: '#app',
data: {
currentComponent: 'component-a'
}
});
</script>
4.6 非同步組件
非同步組件可以按需載入,減少初始載入時間。
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 向 `resolve` 回調傳遞組件定義
resolve({
template: '<div>非同步組件載入成功!</div>'
})
}, 1000)
})
5. Vue Router
5.1 路由基礎
Vue Router 是 Vue.js 的官方路由管理器,用於構建單頁應用。
<!DOCTYPE html>
<html>
<head>
<title>Vue Router 學習</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-router@3"></script>
</head>
<body>
<div id="app">
<router-link to="/home">首頁</router-link>
<router-link to="/about">關於</router-link>
<router-view></router-view>
</div>
<script>
const Home = { template: '<p>首頁</p>' }
const About = { template: '<p>關於</p>' }
const routes = [
{ path: '/home', component: Home },
{ path: '/about', component: About }
]
const router = new VueRouter({
routes
})
var app = new Vue({
el: '#app',
router
});
</script>
</body>
</html>
5.2 動態路由匹配
動態路由匹配允許你在路由路徑中使用參數。
<div id="app">
<router-link to="/user/1">用戶 1</router-link>
<router-link to="/user/2">用戶 2</router-link>
<router-view></router-view>
</div>
<script>
const User = {
template: '<p>用戶 ID: {{ $route.params.id }}</p>'
}
const routes = [
{ path: '/user/:id', component: User }
]
const router = new VueRouter({
routes
})
var app = new Vue({
el: '#app',
router
});
</script>
5.3 嵌套路由
嵌套路由允許你在路由視圖中嵌套其他路由視圖。
<div id="app">
<router-link to="/user/1">用戶 1</router-link>
<router-link to="/user/2">用戶 2</router-link>
<router-view></router-view>
</div>
<script>
const User = {
template: `
<div>
<h2>用戶 ID: {{ $route.params.id }}</h2>
<router-link to="profile">個人資料</router-link>
<router-link to="posts">帖子</router-link>
<router-view></router-view>
</div>
`
}
const UserProfile = { template: '<p>個人資料</p>' }
const UserPosts = { template: '<p>帖子</p>' }
const routes = [
{ path: '/user/:id', component: User,
children: [
{ path: 'profile', component: UserProfile },
{ path: 'posts', component: UserPosts }
]
}
]
const router = new VueRouter({
routes
})
var app = new Vue({
el: '#app',
router
});
</script>
5.4 路由守衛
路由守衛允許你在導航到某個路由之前執行一些邏輯。
<div id="app">
<router-link to="/home">首頁</router-link>
<router-link to="/about">關於</router-link>
<router-view></router-view>
</div>
<script>
const Home = { template: '<p>首頁</p>' }
const About = { template: '<p>關於</p>' }
const routes = [
{ path: '/home', component: Home },
{ path: '/about', component: About, beforeEnter: (to, from, next) => {
if (confirm('你確定要進入關於頁面嗎?')) {
next()
} else {
next(false)
}
}}
]
const router = new VueRouter({
routes
})
var app = new Vue({
el: '#app',
router
});
</script>
5.5 路由元信息
路由元信息允許你在路由配置中添加自定義數據。
<div id="app">
<router-link to="/home">首頁</router-link>
<router-link to="/about">關於</router-link>
<router-view></router-view>
</div>
<script>
const Home = { template: '<p>首頁</p>' }
const About = { template: '<p>關於</p>' }
const routes = [
{ path: '/home', component: Home },
{ path: '/about', component: About, meta: { requiresAuth: true } }
]
const router = new VueRouter({
routes
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// 這裡可以添加你的認證邏輯
if (!auth.isAuthenticated()) {
next({ path: '/login' })
} else {
next()
}
} else {
next()
}
})
var app = new Vue({
el: '#app',
router
});
</script>
5.6 導航守衛
導航守衛可以在路由切換前後執行邏輯。
<div id="app">
<router-link to="/home">首頁</router-link>
<router-link to="/about">關於</router-link>
<router-view></router-view>
</div>
<script>
const Home = { template: '<p>首頁</p>' }
const About = { template: '<p>關於</p>' }
const routes = [
{ path: '/home', component: Home },
{ path: '/about', component: About }
]
const router = new VueRouter({
routes
})
router.beforeEach((to, from, next) => {
console.log('全局前置守衛')
next()
})
router.afterEach((to, from) => {
console.log('全局後置守衛')
})
var app = new Vue({
el: '#app',
router
});
</script>
5.7 路由懶載入
路由懶載入可以按需載入路由組件,減少初始載入時間。
const routes = [
{
path: '/home',
component: () => import('./components/Home.vue')
},
{
path: '/about',
component: () => import('./components/About.vue')
}
]
const router = new VueRouter({
routes
})
6. Vuex 狀態管理
6.1 Vuex 基礎
Vuex 是一個專為 Vue.js 應用設計的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
<!DOCTYPE html>
<html>
<head>
<title>Vuex 學習</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script src="https://cdn.jsdelivr.net/npm/vuex@3"></script>
</head>
<body>
<div id="app">
<p>{{ count }}</p>
<button @click="increment">增加</button>
</div>
<script>
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
var app = new Vue({
el: '#app',
store,
computed: {
count () {
return this.$store.state.count
}
},
methods: {
increment () {
this.$store.commit('increment')
}
}
});
</script>
</body>
</html>
6.2 核心概念
Vuex 的核心概念包括狀態(state)、變更(mutations)、動作(actions)和 getters。
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
}
})
6.3 模塊化
Vuex 允許你將狀態管理邏輯拆分成模塊,每個模塊擁有自己的 state、mutations、actions 和 getters。
const moduleA = {
state: { count: 0 },
mutations: { increment (state) { state.count++ } },
actions: { incrementAsync ({ commit }) { commit('increment') } },
getters: { doubleCount: state => state.count * 2 }
}
const moduleB = {
state: { count: 0 },
mutations: { increment (state) { state.count++ } },
actions: { incrementAsync ({ commit }) { commit('increment') } },
getters: { doubleCount: state => state.count * 2 }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
6.4 中間件
Vuex 支持插件機制,可以在狀態變更時執行一些邏輯。
const myPlugin = store => {
store.subscribe((mutation, state) => {
console.log(mutation.type)
console.log(mutation.payload)
})
}
const store = new Vuex.Store({
state: { count: 0 },
mutations: { increment (state) { state.count++ } },
plugins: [myPlugin]
})
6.5 輔助函數
Vuex 提供了一些輔助函數,幫助你簡化代碼。
<div id="app">
<p>{{ count }}</p>
<button @click="increment">增加</button>
</div>
<script>
const store = new Vuex.Store({
state: { count: 0 },
mutations: { increment (state) { state.count++ } },
actions: { incrementAsync ({ commit }) { commit('increment') } },
getters: { doubleCount: state => state.count * 2 }
})
var app = new Vue({
el: '#app',
store,
computed: Vuex.mapState(['count']),
methods: Vuex.mapMutations(['increment'])
});
</script>
7. 項目實戰
7.1 項目初始化
使用 Vue CLI 初始化一個新的 Vue 項目。
npm install -g @vue/cli
vue create my-project
cd my-project
npm run serve
7.2 組件設計
根據項目需求設計和實現各個組件。假設我們要構建一個簡單的待辦事項應用。
vue create todo-app
cd todo-app
npm run serve
創建 components/TodoItem.vue
:
<template>
<li>
<input type="checkbox" v-model="todo.done">
<span>{{ todo.text }}</span>
</li>
</template>
<script>
export default {
props: ['todo']
}
</script>
創建 components/TodoList.vue
:
<template>
<ul>
<todo-item v-for="todo in todos" :key="todo.id" :todo="todo"></todo-item>
</ul>
</template>
<script>
import TodoItem from './TodoItem.vue'
export default {
components: {
TodoItem
},
data () {
return {
todos: [
{ id: 1, text: '學習 Vue', done: true },
{ id: 2, text: '學習 Vuex', done: false },
{ id: 3, text: '學習 Vue Router', done: false }
]
}
}
}
</script>
在 App.vue
中使用 TodoList
組件:
<template>
<div id="app">
<h1>待辦事項</h1>
<todo-list></todo-list>
</div>
</template>
<script>
import TodoList from './components/TodoList.vue'
export default {
components: {
TodoList
}
}
</script>
7.3 路由配置
使用 Vue Router 配置項目的路由。
安裝 Vue Router:
npm install vue-router
創建 router/index.js
:
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home.vue'
import About from '@/components/About.vue'
Vue.use(Router)
export default new Router({
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
})
在 main.js
中引入路由:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
創建 components/Home.vue
和 components/About.vue
:
Home.vue
:
<template>
<div>
<h1>首頁</h1>
<todo-list></todo-list>
</div>
</template>
<script>
import TodoList from './TodoList.vue'
export default {
components: {
TodoList
}
}
</script>
About.vue
:
<template>
<div>
<h1>關於</h1>
<p>這是關於頁面。</p>
</div>
</template>
7.4 狀態管理
使用 Vuex 管理項目的全局狀態。
安裝 Vuex:
npm install vuex
創建 store/index.js
:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
todos: [
{ id: 1, text: '學習 Vue', done: true },
{ id: 2, text: '學習 Vuex', done: false },
{ id: 3, text: '學習 Vue Router', done: false }
]
},
mutations: {
addTodo (state, todo) {
state.todos.push(todo)
}
},
actions: {
addTodo ({ commit }, todo) {
commit('addTodo', todo)
}
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
在 main.js
中引入 Vuex:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
在 TodoList.vue
中使用 Vuex 狀態:
<template>
<ul>
<todo-item v-for="todo in todos" :key="todo.id" :todo="todo"></todo-item>
</ul>
</template>
<script>
import TodoItem from './TodoItem.vue'
import { mapState } from 'vuex'
export default {
components: {
TodoItem
},
computed: {
...mapState(['todos'])
}
}
</script>
7.5 API 集成
假設我們有一個簡單的 API 來獲取和添加待辦事項。
創建 api/todos.js
:
import axios from 'axios'
const API_URL = 'http://example.com/api/todos'
export default {
getTodos () {
return axios.get(API_URL)
},
addTodo (todo) {
return axios.post(API_URL, todo)
}
}
在 Vuex 中使用 API:
import Vue from 'vue'
import Vuex from 'vuex'
import api from '@/api/todos'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
todos: []
},
mutations: {
setTodos (state, todos) {
state.todos = todos
},
addTodo (state, todo) {
state.todos.push(todo)
}
},
actions: {
fetchTodos ({ commit }) {
api.getTodos().then(response => {
commit('setTodos', response.data)
})
},
addTodo ({ commit }, todo) {
api.addTodo(todo).then(response => {
commit('addTodo', response.data)
})
}
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
在組件中觸發 API 請求:
<template>
<div>
<ul>
<todo-item v-for="todo in todos" :key="todo.id" :todo="todo"></todo-item>
</ul>
<input v-model="newTodoText" placeholder="添加新任務">
<button @click="addTodo">添加</button>
</div>
</template>
<script>
import TodoItem from './TodoItem.vue'
import { mapState, mapActions } from 'vuex'
export default {
components: {
TodoItem
},
data() {
return {
newTodoText: ''
}
},
computed: {
...mapState(['todos'])
},
methods: {
...mapActions(['fetchTodos', 'addTodo']),
addTodo() {
const newTodo = {
text: this.newTodoText,
done: false
}
this.addTodo(newTodo)
this.newTodoText = ''
}
},
created() {
this.fetchTodos()
}
}
</script>
7.6 部署與優化
將項目部署到生產環境,併進行性能優化。
- 構建項目:
npm run build
- 部署到伺服器:
將 dist
目錄中的內容上傳到你的伺服器。
- 性能優化:
- 使用 Vue Router 的懶載入功能按需載入組件。
- 使用 Vuex 的模塊化功能減少狀態管理的複雜性。
- 使用 Webpack 的代碼分割功能減少初始載入時間。
- 使用 gzip 壓縮減少傳輸數據量。
8. 進階概念
8.1 自定義指令
自定義指令允許你在 DOM 元素上應用自定義行為。
Vue.directive('focus', {
inserted: function (el) {
el.focus()
}
})
在組件中使用自定義指令:
<template>
<input v-focus>
</template>
8.2 混入
混入提供了一種分發 Vue 組件可復用功能的非常靈活的方式。
const myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('Hello from mixin!')
}
}
}
const Component = Vue.extend({
mixins: [myMixin]
})
8.3 插件
插件是 Vue.js 的一個核心概念,用於為 Vue 添加全局功能。
const MyPlugin = {
install (Vue, options) {
Vue.mixin({
created: function () {
console.log('Hello from plugin!')
}
})
}
}
Vue.use(MyPlugin)
8.4 服務端渲染 (SSR)
Vue.js 也支持服務端渲染(SSR),用於提升首屏載入速度和 SEO。
安裝 Vue SSR 工具:
npm install vue-server-renderer express
創建 server.js
:
const express = require('express')
const renderer = require('vue-server-renderer').createRenderer()
const createApp = require('./path/to/your/app')
const server = express()
server.get('*', (req, res) => {
const app = createApp()
renderer.renderToString(app, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error')
return
}
res.end(`
<!DOCTYPE html>
<html lang="en">
<head><title>Hello</title></head>
<body>${html}</body>
</html>
`)
})
})
server.listen(8080)
8.5 Vue 3 新特性
Vue 3 引入了一些新的特性和改進,包括組合式 API、性能優化、TypeScript 支持等。
組合式 API
組合式 API 提供了一種更靈活的方式來組織組件邏輯。
<template>
<div>
<p>{{ count }}</p>
<button @click="increment">增加</button>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
const increment = () => {
count.value++
}
return {
count,
increment
}
}
}
</script>
9. 總結與展望
通過本書的學習,你應該已經掌握了 Vue.js 的基礎知識和一些高級特性。希望你能將這些知識應用到實際項目中,不斷實踐和探索,成為一名優秀的 Vue.js 開發者。未來,Vue.js 生態系統還會不斷發展,期待你能持續關註和學習。