一、引言
Vue 是一款用于構建用戶界面的漸進式 JavaScript 框架,具有易上手、高性能、靈活等特點,能夠幫助開發者快速開發出響應式的單頁面應用。本技術文檔旨在全面介紹 Vue 的相關技術知識,為開發人員提供參考和指導。
二、環境搭建
2.1 安裝 Node.js
Vue 的開發依賴 Node.js 環境,可以從官方下載地址下載適合你操作系統的安裝包進行安裝,在安裝過程中,會自動將 Node.js 以及 npm(Node.js 的包管理工具)安裝到你的系統中。
安裝完成后,可以通過在命令行中輸入以下命令來驗證安裝是否成功:
node -v
npm -v
分別查看 Node.js 和 npm 的版本號,若能正常顯示版本號,則說明安裝成功。
2.2 安裝 Vue CLI
Vue CLI 是 Vue 的命令行工具,可以幫助我們快速創建和管理 Vue 項目。安裝命令如下:
npm install -g @vue/cli
安裝完成后,可以通過以下命令查看 Vue CLI 的版本號,驗證安裝是否成功:
vue --version
2.3 創建 Vue 項目
在命令行中運行以下命令來創建一個新的 Vue 項目:
vue create my-vue-project
其中,“my-vue-project” 是你項目的名稱,可以根據實際情況進行替換。在執行該命令后,會提示你選擇項目配置選項,包括預設、路由、Vuex(狀態管理)、CSS 預處理器等,你可以根據項目需求進行選擇。
待配置選擇完成后,進入項目目錄:
cd my-vue-project
然后啟動開發服務器:
npm run serve
此時,開發服務器會啟動并在瀏覽器中自動打開項目頁面,通常訪問地址為http://localhost:8080
,你就可以看到新創建的 Vue 項目的基礎頁面了。
三、項目文件結構
一個典型的 Vue 項目文件結構如下:
my-vue-project/
├── node_modules/ // 項目依賴的第三方模塊
├── public/ // 靜態資源目錄
│ ├── index.html // 入口 HTML 文件
│ └── favicon.ico // 網站圖標
├── src/ // 源代碼目錄
│ ├── assets/ // 項目靜態資源,如圖片、樣式文件等
│ ├── components/ // Vue 組件文件夾
│ ├── views/ // Vue 頁面文件夾
│ ├── App.vue // 項目的根組件
│ ├── main.js // 項目的入口 JavaScript 文件
│ └── router.js // 路由配置文件
├── .browserslistrc // 瀏覽器兼容性配置文件
├── .eslintrc.js // ESLint 配置文件,用于代碼規范檢查
├── .gitignore // Git 忽略文件配置
├── babel.config.js // Babel 配置文件,用于 JavaScript 代碼的轉譯
├── package.json // 項目配置文件,包含項目依賴、腳本等信息
└── README.md // 項目的說明文檔
四、Vue 核心概念
4.1 Vue 實例
一個 Vue 應用是由一個 Vue 實例創建的,基本語法如下:
new Vue({el: '#app', // 指定 Vue 實例掛載的 DOM 元素,通常是一個具有特定 id 的元素data: { // 數據對象,用于存儲 Vue 實例中的數據,這些數據會在視圖中進行展示,并且當數據發生變化時,視圖會自動更新message: 'Hello Vue!'},methods: { // 方法對象,定義 Vue 實例中的函數,可以通過事件綁定等方式來調用這些方法,實現用戶交互等功能sayHello: function () {console.log(this.message);}}
});
在 HTML 中通過雙花括號語法綁定數據:
<div id="app"><p>{{ message }}</p> <!-- 這里會顯示 data 中的 message 數據 --><button @click="sayHello">點擊</button> <!-- 點擊按鈕時會調用 methods 中的 sayHello 方法 -->
</div>
當點擊按鈕時,會調用 sayHello
方法并輸出 “Hello Vue!”。
4.2 數據綁定
Vue 提供了多種數據綁定方式,常見的有以下幾種:
4.2.1 文本綁定
使用雙花括號語法 {{ }}
將數據綁定到文本內容中,例如:
<p>{{ message }}</p>
當 data
中的 message
數據發生變化時,頁面上的文本內容會自動更新。
4.2.2 屬性綁定
使用 v-bind
指令(可以簡寫為 :
)將數據綁定到 HTML 元素的屬性上,例如:
<img :src="imageSrc" alt="示例圖片">
其中,imageSrc
是 data
中的一個數據項,表示圖片的路徑,當 imageSrc
的值改變時,圖片會自動更新。
4.2.3 表單綁定
使用 v-model
指令實現表單元素(如輸入框、復選框、單選按鈕等)與數據的雙向綁定,例如:
<input v-model="inputValue" type="text">
當用戶在輸入框中輸入內容時,data
中的 inputValue
數據會實時更新;反之,如果 inputValue
數據發生變化(如通過代碼修改),輸入框中的內容也會相應地更新。
4.3 指令
指令是 Vue 中帶有 v-
前綴的特殊屬性,用于在 HTML 中聲明式地綁定數據和執行操作。
4.3.1 條件指令
v-if
用于根據表達式值的真假來控制元素的顯示與隱藏,例如:
<div v-if="isVisible">只有當 isVisible 為 true 時才顯示</div>
v-else
用于表示 v-if
的對立條件,例如:
<div v-if="isLoggedIn">已登錄</div>
<div v-else>未登錄</div>
v-show
也是根據表達式值的真假來控制元素的顯示與隱藏,但它始終會渲染元素到 HTML 中,只是通過 CSS 的 display
屬性來切換顯示狀態,與 v-if
不同的是,v-if
是通過銷毀和重建 DOM 元素來實現顯示隱藏的,性能消耗較大,但 v-show
不適合頻繁切換的情況,例如:
<div v-show="isVisible">內容</div>
4.3.2 循環指令
v-for
用于根據數組或對象來渲染列表,例如:
<ul><li v-for="(item, index) in items" :key="index">{{ item }}</li>
</ul>
其中,items
是 data
中的一個數組,v-for
會遍歷數組中的每個元素,并為每個元素生成一個 <li>
元素,index
表示元素在數組中的索引位置,key
是一個特殊的屬性,用于給每個列表元素提供一個唯一的標識,有助于 Vue 更高效地進行 DOM 更新。
對于對象的循環也是類似的,例如:
<div v-for="(value, key, index) in object" :key="index">{{ key }}: {{ value }}
</div>
其中,object
是 data
中的一個對象,key
表示對象的屬性名,value
表示對應的屬性值,index
表示對象屬性的索引。
4.4 組件
組件是 Vue 中的核心概念之一,它允許我們將界面拆分成獨立、可復用的部分,每個組件都有自己的模板、邏輯和樣式,提高了代碼的組織性和可維護性。
4.4.1 組件的創建
可以通過 Vue.component()
方法全局注冊一個組件,例如:
Vue.component('my-component', {template: '<div>這是一個全局組件</div>'
});
然后在任何一個 Vue 實例管理的 DOM 中都可以使用 <my-component>
來渲染該組件。
也可以在單個 Vue 實例中局部注冊組件,例如:
new Vue({el: '#app',components: {'local-component': {template: '<div>這是一個局部組件</div>'}}
});
這樣,這個組件只能在該 Vue 實例所管理的范圍內使用。
不過,在實際開發中,尤其是大型項目中,我們通常會使用單文件組件(.vue 文件)來定義組件,這種文件將組件的模板、腳本和樣式集中在一個文件中,結構清晰,便于管理和復用。例如,一個名為 MyComponent.vue
的文件內容如下:
<template><div><h2>{{ title }}</h2><p>{{ content }}</p></div>
</template><script>
export default {name: 'MyComponent',data() {return {title: '組件標題',content: '組件內容'};}
};
</script><style scoped>
div {border: 1px solid #ccc;padding: 10px;margin: 10px;
}
</style>
其中,<template>
部分定義了組件的 HTML 模板結構,<script>
部分定義了組件的邏輯部分,包括數據、方法、生命周期等,<style scoped>
部分定義了組件的局部樣式,scoped
屬性使得這些樣式只作用于該組件的模板部分,而不會影響到其他組件或頁面中的元素。
4.4.2 組件的注冊與使用
對于單文件組件,需要先將其導入到使用它的 Vue 文件中,然后再進行注冊,才能使用。例如,在 main.js
中導入和注冊組件:
import Vue from 'vue';
import App from './App.vue';
import MyComponent from './components/MyComponent.vue';Vue.config.productionTip = false;
Vue.component('my-component', MyComponent);new Vue({render: h => h(App),
}).$mount('#app');
這樣,在項目的任何 Vue 組件中都可以使用 <my-component>
標簽來渲染該組件。
4.4.3 父子組件通信
4.4.3.1 父組件向子組件傳遞數據
通過 props
屬性來實現父組件向子組件傳遞數據,子組件通過 props
選項接收父組件傳遞的數據。例如,在父組件中:
<child-component :parent-message="message"></child-component>
其中,:parent-message
是綁定的屬性名,它會將父組件中的 message
數據傳遞給子組件,注意這里的 :parent-message
是動態綁定的,如果父組件的 message
數據發生變化,子組件會自動接收到新的值。
在子組件中,通過 props
選項接收:
props: ['parentMessage']
然后在子組件的模板中就可以使用 parentMessage
來展示該數據了。
4.4.3.2 子組件向父組件傳遞數據
子組件可以通過 $emit
方法來觸發一個自定義事件,并將數據作為事件的參數傳遞給父組件,父組件通過監聽該事件來接收子組件傳遞的數據。例如,在子組件中:
this.$emit('child-event', data);
其中,child-event
是自定義事件名,data
是要傳遞的數據。
在父組件中監聽該事件:
<child-component @child-event="handleChildEvent"></child-component>
然后在父組件的 methods
中定義 handleChildEvent
方法來處理子組件傳遞過來的數據:
methods: {handleChildEvent(data) {console.log('子組件傳遞的數據:', data);}
}
五、Vue 路由(Vue Router)
Vue Router 是 Vue 官方的路由管理器,它允許我們構建單頁面應用(SPA),通過定義不同的路由規則,將不同的組件映射到不同的 URL 地址,實現頁面的切換和數據的保持。
5.1 安裝 Vue Router
可以通過 npm 安裝 Vue Router,命令如下:
npm install vue-router
5.2 創建路由配置文件
在項目中創建一個路由配置文件,例如 router.js
,內容如下:
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from './views/Home.vue'; // 引入主頁組件
import About from './views/About.vue'; // 引入關于頁面組件
import User from './views/User.vue'; // 引入用戶頁面組件Vue.use(VueRouter); // 安裝路由插件const routes = [{path: '/',name: 'home',component: Home},{path: '/about',name: 'about',component: About},{path: '/user/:id', // 帶參數的路由,:id 表示動態參數name: 'user',component: User}
];const router = new VueRouter({mode: 'history', // 使用 history 模式,這樣 URL 地址看起來更整潔,沒有 # 號base: process.env.BASE_URL, // 基礎路徑routes
});export default router;
5.3 在主文件中引入路由
在 main.js
中引入路由配置文件,并將其掛載到 Vue 實例上:
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');
5.4 使用路由鏈接和視圖
在應用中,我們使用 <router-link>
組件來創建導航鏈接,使用 <router-view>
組件作為路由出口,渲染對應的組件。例如:
<div id="app"><nav><router-link to="/">首頁</router-link> |<router-link to="/about">關于</router-link> |<router-link :to="{ name: 'user', params: { id: 123 }}">用戶 123</router-link> |<router-link :to="{ path: '/user/456' }">用戶 456</router-link></nav><router-view></router-view>
</div>
當用戶點擊不同的鏈接時,<router-view>
中會根據當前的路由路徑渲染對應的組件。
5.5 路由傳參(就個人喜好選擇)
在前面的示例中,我們已經看到了通過路由傳參的方法,即在路由路徑中定義動態參數(如 /user/:id
),然后在組件中通過 this.$route.params
來獲取參數值,例如在 User.vue
組件中:
export default {name: 'User',mounted() {const userId = this.$route.params.id;console.log('用戶 ID:', userId);// 可以根據 userId 去獲取對應的用戶數據并進行展示}
}
此外,還可以通過查詢參數的形式進行傳參,例如:
<router-link :to="{ path: '/about', query: { name: 'Vue', version: '3.x' }}">關于</router-link>
在組件中通過 this.$route.query
獲取查詢參數:
mounted() {const { name, version } = this.$route.query;console.log('查詢參數:', name, version);
}
六、狀態管理(Vuex)
Vuex 是 Vue 官方的狀態管理模式,它采用集中式存儲管理應用的所有組件的狀態,并以相應的規則保證狀態以一種可預測的方式發生變化,適用于中大型的 Vue 項目,幫助我們更好地管理共享狀態。
6.1 安裝 Vuex
同樣,可以通過 npm 安裝 Vuex,命令如下:
npm install vuex
6.2 創建 Vuex Store
在項目中創建一個 store.js
文件,定義 Vuex 的狀態存儲:
import Vue from 'vue';
import Vuex from 'vuex';Vue.use(Vuex); // 安裝 Vuex 插件export default new Vuex.Store({state: {count: 0, // 狀態數據todos: [ // 列表數據{ id: 1, text: '學習 Vue', done: true },{ id: 2, text: '學習 Vuex', done: false }]},mutations: {// mutations 是同步的方法,用于修改 state 中的狀態,必須通過提交 mutation 來修改狀態increment(state) {state.count++;},decrement(state) {state.count--;},addTodo(state, todo) {state.todos.push(todo);},toggleTodo(state, id) {const todo = state.todos.find(todo => todo.id === id);if (todo) {todo.done = !todo.done;}}},actions: {// actions 類似于 mutations,但是 actions 可以包含異步操作,它提交 mutation 來改變狀態incrementAsync({ commit }) {setTimeout(() => {commit('increment');}, 1000);},addTodoAsync({ commit }, todo) {setTimeout(() => {commit('addTodo', todo);}, 1000);}},getters: {// getters 可以對 state 進行計算或過濾等操作,類似于 Vue 實例中的 computed 屬性doubleCount(state) {return state.count * 2;},doneTodos(state) {return state.todos.filter(todo => todo.done);},doneTodosCount: (state) => {return state.todos.filter(todo => todo.done).length;}}
});
6.3 在 Vue 實例中使用 Store
在 main.js
中引入并掛載 Vuex Store:
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store'; // 引入 Vuex StoreVue.config.productionTip = false;new Vue({router,store, // 掛載 Vuex Storerender: h => h(App)
}).$mount('#app');
6.4 在組件中使用 Vuex 狀態
6.4.1 讀取狀態
在組件中可以通過 this.$store.state
來訪問 Vuex Store 中的狀態,例如:
export default {computed: {count() {return this.$store.state.count;},todos() {return this.$store.state.todos;}}
}
也可以通過 Vuex 提供的 mapState
輔助函數來簡化代碼:
import { mapState } from 'vuex';export default {computed: mapState({count: state => state.count,todos: state => state.todos})
}
或者更簡潔的寫法:
import { mapState } from 'vuex';export default {computed: mapState(['count', 'todos'])
}
6.4.2 提交 mutations 修改狀態
要修改 Vuex Store 中的狀態,必須通過提交 mutation。在組件中可以通過 this.$store.commit
方法來提交 mutation,例如:
methods: {incrementCount() {this.$store.commit('increment');},decrementCount() {this.$store.commit('decrement');},addTodo() {const newTodo = { id: 3, text: '學習 Vue Router', done: false };this.$store.commit('addTodo', newTodo);},toggleTodo(id) {this.$store.commit('toggleTodo', id);}
}
同樣,可以使用 Vuex 提供的 mapMutations
輔助函數來簡化代碼:
import { mapMutations } from 'vuex';export default {methods: {...mapMutations(['increment', 'decrement']),addTodo() {const newTodo = { id: 3, text: '學習 Vue Router', done: false };this.$store.commit('addTodo', newTodo);},toggleTodo(id) {this.$store.commit('toggleTodo', id);}}
}
-------------------------------------------混入和過濾器等跳過
十、Vue 的插槽(Slots)
插槽是 Vue 中用于內容分發的機制,允許父組件向子組件的特定位置插入內容。
10.1 單插槽
在子組件中定義插槽:
<template><div><h2>這是一個子組件</h2><slot></slot> <!-- 定義插槽 --></div>
</template>
在父組件中使用子組件并插入內容:
<child-component><p>這是父組件插入的內容,會顯示在子組件的插槽位置。</p>
</child-component>
10.2 具名插槽
當子組件中有多個插槽時,可以通過 name
屬性來區分它們,即具名插槽。例如,子組件中:
<template><div><h2>這是一個子組件</h2><slot name="header"></slot> <!-- 定義具名插槽 --><div class="content"><slot name="content"></slot></div></div>
</template>
父組件中使用:
<child-component><template v-slot:header><h3>這是頭部內容</h3></template><template v-slot:content><p>這是內容區域的內容</p></template>
</child-component>
或者使用更簡潔的語法:
<child-component><h3 slot="header">這是頭部內容</h3><p slot="content">這是內容區域的內容</p>
</child-component>
10.3 作用域插槽
作用域插槽允許父組件在插入內容時能夠訪問子組件中的一些數據,即子組件可以向父組件傳遞數據,供父組件在插槽中使用。例如,子組件中:
<template><div><h2>列表組件</h2><ul><li v-for="(item, index) in items" :key="index"><slot :item="item" :index="index"></slot></li></ul></div>
</template><script>
export default {data() {return {items: ['蘋果', '香蕉', '橙子', '葡萄']};}
};
</script>
父組件中使用:
<list-component><template v-slot="slotProps"><p>第 {{ slotProps.index + 1 }} 項:{{ slotProps.item }}</p></template>
</list-component>
此時,父組件可以通過 slotProps
訪問到子組件傳遞過來的 item
和 index
數據,用于渲染列表項內容。
其實這三個插槽本質都是一個插槽,不管參數或者name是什么樣的,最后的結果是三者是一個變式的關系。