vue init webpack hello-vue
安裝依賴css
# 進入工程目錄 cd hello-vue # 安裝 vue-router npm install vue-router --save-dev # 安裝 element-ui npm i element-ui -S # 安裝 SASS 加載器 npm install sass-loader node-sass --save-dev # 安裝依賴 npm install
npm install moduleName
:安裝模塊到項目目錄下npm install -g moduleName
:-g 的意思是將模塊安裝到全局,具體安裝到磁盤哪一個位置,要看 npm config prefix 的位置npm install -save moduleName
:--save 的意思是將模塊安裝到項目目錄下,並在 package 文件的 dependencies 節點寫入依賴,-S
爲該命令的縮寫npm install -save-dev moduleName
:--save-dev 的意思是將模塊安裝到項目目錄下,並在 package 文件的 devDependencies 節點寫入依賴,-D
爲該命令的縮寫npm run dev
iview 是一個強大的基於 Vue 的 UI 庫,有不少實用的基礎組件比 elementui 的組件更豐富,主要服務於 PC 界面的中後臺產品。使用單文件的 Vue 組件化開發模式 基於 npm + webpack + babel 開發,支持 ES2015 高質量、功能豐富 友好的 API ,自由靈活地使用空間。前端
備註:屬於前端主流框架,選型時可考慮使用,主要特色是移動端支持較多vue
Element 是餓了麼前端開源維護的 Vue UI 組件庫,組件齊全,基本涵蓋後臺所需的全部組件,文檔講解詳細,例子也很豐富。主要用於開發 PC 端的頁面,是一個質量比較高的 Vue UI 組件庫。java
備註:屬於前端主流框架,選型時可考慮使用,主要特色是桌面端支持較多node
在 views
目錄下建立一個名爲 Main.vue
的視圖組件;該組件在當前章節無任何做用,主要用於登陸後展現登陸成功的跳轉效果;webpack
<template> <div> 首頁 </div> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
在 views
目錄下建立一個名爲 Login.vue
的視圖組件,其中 el-*
的元素爲 ElementUI 組件;ios
<template> <div> <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box"> <h3 class="login-title">歡迎登陸</h3> <el-form-item label="帳號" prop="username"> <el-input type="text" placeholder="請輸入帳號" v-model="form.username"/> </el-form-item> <el-form-item label="密碼" prop="password"> <el-input type="password" placeholder="請輸入密碼" v-model="form.password"/> </el-form-item> <el-form-item> <el-button type="primary" v-on:click="onSubmit('loginForm')">登陸</el-button> </el-form-item> </el-form> <el-dialog title="舒適提示" :visible.sync="dialogVisible" width="30%" :before-close="handleClose"> <span>請輸入帳號和密碼</span> <span slot="footer" class="dialog-footer"> <el-button type="primary" @click="dialogVisible = false">確 定</el-button> </span> </el-dialog> </div> </template> <script> export default { name: "Login", data() { return { form: { username: '', password: '' }, // 表單驗證,須要在 el-form-item 元素中增長 prop 屬性 rules: { username: [ {required: true, message: '帳號不可爲空', trigger: 'blur'} ], password: [ {required: true, message: '密碼不可爲空', trigger: 'blur'} ] }, // 對話框顯示和隱藏 dialogVisible: false } }, methods: { onSubmit(formName) { // 爲表單綁定驗證功能 this.$refs[formName].validate((valid) => { if (valid) { // 使用 vue-router 路由到指定頁面,該方式稱之爲編程式導航 this.$router.push("/main"); } else { this.dialogVisible = true; return false; } }); } } } </script> <style lang="scss" scoped> .login-box { border: 1px solid #DCDFE6; width: 350px; margin: 180px auto; padding: 35px 35px 15px 35px; border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; box-shadow: 0 0 25px #909399; } .login-title { text-align: center; margin: 0 auto 40px auto; color: #303133; } </style>
在 router
目錄下建立一個名爲 index.js
的 vue-router 路由配置文件git
import Vue from 'vue' import Router from 'vue-router' import Login from "../views/Login" import Main from '../views/Main' Vue.use(Router); export default new Router({ routes: [ { // 登陸頁 path: '/login', name: 'Login', component: Login }, { // 首頁 path: '/main', name: 'Main', component: Main } ] });
修改 main.js
入口代碼github
import Vue from 'vue' import VueRouter from 'vue-router' import router from './router' // 導入 ElementUI import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' import App from './App' // 安裝路由 Vue.use(VueRouter); // 安裝 ElementUI Vue.use(ElementUI); new Vue({ el: '#app', // 啓用路由 router, // 啓用 ElementUI render: h => h(App) });
修改 App.vue
組件代碼web
<template> <div id="app"> <router-view/> </div> </template> <script> export default { name: 'App', } </script>
嵌套路由又稱子路由,在實際應用中,一般由多層嵌套的組件組合而成。一樣地,URL 中各段動態路徑也按某種結構對應嵌套的各層組件。
在 views/user
目錄下建立一個名爲 Profile.vue
的視圖組件;該組件在當前章節無任何做用,主要用於展現嵌套效果;
<template> <div> 我的信息 </div> </template> <script> export default { name: "UserProfile" } </script> <style scoped> </style>
在 views/user
目錄下建立一個名爲 List.vue
的視圖組件;該組件在當前章節無任何做用,主要用於展現嵌套效果;
<template> <div> 用戶列表 </div> </template> <script> export default { name: "UserList" } </script> <style scoped> </style>
修改 router
目錄下的 index.js
路由配置文件,代碼以下:
import Vue from 'vue' import Router from 'vue-router' import Login from "../views/Login" import Main from '../views/Main' // 用於嵌套的路由組件 import UserProfile from '../views/user/Profile' import UserList from '../views/user/List' Vue.use(Router); export default new Router({ routes: [ { // 登陸頁 path: '/login', name: 'Login', component: Login }, { // 首頁 path: '/main', name: 'Main', component: Main, // 配置嵌套路由 children: [ {path: '/user/profile', component: UserProfile}, {path: '/user/list', component: UserList}, ] } ] });
說明:主要在路由配置中增長了 children
數組配置,用於在該組件下設置嵌套路由
接着上一節的代碼,咱們修改 Main.vue
視圖組件,此處使用了 ElementUI 佈局容器組件,代碼以下:
<template> <div> <el-container> <el-aside width="200px"> <el-menu :default-openeds="['1']"> <el-submenu index="1"> <template slot="title"><i class="el-icon-caret-right"></i>用戶管理</template> <el-menu-item-group> <el-menu-item index="1-1"> <router-link to="/user/profile">我的信息</router-link> </el-menu-item> <el-menu-item index="1-2"> <router-link to="/user/list">用戶列表</router-link> </el-menu-item> </el-menu-item-group> </el-submenu> <el-submenu index="2"> <template slot="title"><i class="el-icon-caret-right"></i>內容管理</template> <el-menu-item-group> <el-menu-item index="2-1">分類管理</el-menu-item> <el-menu-item index="2-2">內容列表</el-menu-item> </el-menu-item-group> </el-submenu> </el-menu> </el-aside> <el-container> <el-header style="text-align: right; font-size: 12px"> <el-dropdown> <i class="el-icon-setting" style="margin-right: 15px"></i> <el-dropdown-menu slot="dropdown"> <el-dropdown-item>我的信息</el-dropdown-item> <el-dropdown-item>退出登陸</el-dropdown-item> </el-dropdown-menu> </el-dropdown> <span>Lusifer</span> </el-header> <el-main> <router-view /> </el-main> </el-container> </el-container> </div> </template> <script> export default { name: "Main" } </script> <style scoped lang="scss"> .el-header { background-color: #B3C0D1; color: #333; line-height: 60px; } .el-aside { color: #333; } </style>
說明:
<el-main>
元素中配置了 <router-view />
用於展現嵌套路由<router-link to="/user/profile">我的信息</router-link>
展現嵌套路由內容咱們常常須要把某種模式匹配到的全部路由,全都映射到同個組件。例如,咱們有一個 User 組件,對於全部 ID 各不相同的用戶,都要使用這個組件來渲染。此時咱們就須要傳遞參數了;
{path: '/user/profile/:id', name:'UserProfile', component: UserProfile}
說明:主要是在 path
屬性中增長了 :id
這樣的佔位符
<router-link :to="{name: 'UserProfile', params: {id: 1}}">我的信息</router-link>
說明:此時咱們將 to
改成了 :to
,是爲了將這一屬性當成對象使用,注意 router-link 中的 name 屬性名稱 必定要和 路由中的 name 屬性名稱 匹配,由於這樣 Vue 才能找到對應的路由路徑;
this.$router.push({ name: 'UserProfile', params: {id: 1}});
在目標組件中使用
{{ $route.params.id }}
props
的方式{path: '/user/profile/:id', name:'UserProfile', component: UserProfile, props: true}
說明:主要增長了 props: true
屬性
同上
爲目標組件增長 props
屬性,代碼以下:
export default { props: ['id'], name: "UserProfile" }
模板中使用
{{ id }}
{ path: '/main', name: 'Main', component: Main }, { path: '/goHome', redirect: '/main' }
說明:這裏定義了兩個路徑,一個是 /main
,一個是 /goHome
,其中 /goHome
重定向到了 /main
路徑,由此能夠看出重定向不須要定義組件;
設置對應路徑便可
<router-link to="/goHome">回到首頁</router-link>
{ // 首頁 path: '/main/:username', name: 'Main', component: Main }, { path: '/goHome/:username', redirect: '/main/:username' }
<router-link to="/goHome/Lusifer">回到首頁</router-link>
路由模式有兩種
#
符號,如 http://localhost/#/login
#
符號,如 http://localhost/login
修改路由配置,代碼以下:
export default new Router({ mode: 'history', routes: [ ] });
建立一個名爲 NotFound.vue
的視圖組件,代碼以下:
<template> <div> 頁面不存在,請重試! </div> </template> <script> export default { name: "NotFount" } </script> <style scoped> </style>
修改路由配置,代碼以下:
{ path: '*', component: NotFound }
beforeRouteEnter
:在進入路由前執行beforeRouteLeave
:在離開路由前執行案例代碼以下:
export default { props: ['id'], name: "UserProfile", beforeRouteEnter: (to, from, next) => { console.log("準備進入我的信息頁"); next(); }, beforeRouteLeave: (to, from, next) => { console.log("準備離開我的信息頁"); next(); } }
參數說明:
to
:路由將要跳轉的路徑信息from
:路徑跳轉前的路徑信息next
:路由的控制參數
next()
跳入下一個頁面next('/path')
改變路由的跳轉方向,使其跳到另外一個路由next(false)
返回原來的頁面next((vm)=>{})
僅在 beforeRouteEnter 中可用,vm 是組件實例安裝 Axios
npm install axios -s
引用 Axios(修改main.js)
import axios from 'axios' Vue.prototype.axios = axios;
在 beforeRouteEnter
中進行異步請求,案例代碼以下:
export default { props: ['id'], name: "UserProfile", beforeRouteEnter: (to, from, next) => { console.log("準備進入我的信息頁"); // 注意,必定要在 next 中請求,由於該方法調用時 Vue 實例尚未建立,此時沒法獲取到 this 對象,在這裏使用官方提供的回調函數拿到當前實例 next(vm => { vm.getData(); }); }, beforeRouteLeave: (to, from, next) => { console.log("準備離開我的信息頁"); next(); }, methods: { getData: function () { this.axios({ method: 'get', url: 'http://localhost:8080/data.json' }).then(function (repos) { console.log(repos); }).catch(function (error) { console.log(error); }); } } }
Vuex 是一個專爲 Vue.js 應用程序開發的 狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
繼續以前 vue-router 章節作的案例項目,咱們經過完善登陸功能將用戶信息保存至 Vuex 中來體會它的做用;
在項目根目錄執行以下命令來安裝 Vuex
咱們利用路由鉤子 beforeEach
來判斷用戶是否登陸,期間會用到 sessionStorage
存儲功能
Login.vue
在表單驗證成功方法內增長以下代碼:
// 設置用戶登陸成功 sessionStorage.setItem('isLogin', 'true');
main.js
利用路由鉤子 beforeEach
方法判斷用戶是否成功登陸,關鍵代碼以下:
// 在跳轉前執行 router.beforeEach((to, form, next) => { // 獲取用戶登陸狀態 let isLogin = sessionStorage.getItem('isLogin'); // 註銷 if (to.path == '/logout') { // 清空 sessionStorage.clear(); // 跳轉到登陸 next({path: '/login'}); } // 若是請求的是登陸頁 else if (to.path == '/login') { if (isLogin != null) { // 跳轉到首頁 next({path: '/main'}); } } // 若是爲非登陸狀態 else if (isLogin == null) { // 跳轉到登陸頁 next({path: '/login'}); } // 下一個路由 next(); });
vuex
在 src
目錄下建立一個名爲 store
的目錄並新建一個名爲 index.js
文件用來配置 Vuex,代碼以下:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); // 全局 state 對象,用於保存全部組件的公共數據 const state = { // 定義一個 user 對象 // 在組件中是經過 this.$store.state.user 來獲取 user: { username: '' } }; // 實時監聽 state 值的最新狀態,注意這裏的 getters 能夠理解爲計算屬性 const getters = { // 在組件中是經過 this.$store.getters.getUser 來獲取,頁面上使用{{$store.getters.getUser.username}}來獲取 getUser(state) { return state.user; } }; // 定義改變 state 初始值的方法,這裏是惟一能夠改變 state 的地方,缺點是隻能同步執行 const mutations = { // 在組件中是經過 this.$store.commit('updateUser', user); 方法來調用 mutations updateUser(state, user) { state.user = user; } }; // 定義觸發 mutations 裏函數的方法,能夠異步執行 mutations 裏的函數 const actions = { // 在組件中是經過 this.$store.dispatch('asyncUpdateUser', user); 來調用 actions asyncUpdateUser(context, user) { context.commit('updateUser', user); } }; export default new Vuex.Store({ state, getters, mutations, actions });
修改 main.js
增長剛纔配置的 store/index.js
,關鍵代碼以下:
import Vue from 'vue' import Vuex from 'vuex' import store from './store' Vue.use(Vuex); new Vue({ el: '#app', store });
Vuex 的狀態存儲是響應式的,當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的組件也會相應地獲得高效更新。可是有一個問題就是:vuex 的存儲的數據只是在頁面的中,至關於咱們定義的全局變量,刷新以後,裏邊的數據就會恢復到初始化狀態。可是這個狀況有時候並非咱們所但願的。
監聽頁面是否刷新,若是頁面刷新了,將 state 對象存入到 sessionStorage 中。頁面打開以後,判斷 sessionStorage 中是否存在 state 對象,若是存在,則說明頁面是被刷新過的,將 sessionStorage 中存的數據取出來給 vuex 中的 state 賦值。若是不存在,說明是第一次打開,則取 vuex 中定義的 state 初始值。
在 App.vue
中增長監聽刷新事件
export default { name: 'App', mounted() { window.addEventListener('unload', this.saveState); }, methods: { saveState() { sessionStorage.setItem('state', JSON.stringify(this.$store.state)); } } }
修改 store/index.js
中的 state
const state = sessionStorage.getItem('state') ? JSON.parse(sessionStorage.getItem('state')) : { user: { username: '' } };
因爲使用單一狀態樹,應用的全部狀態會集中到一個比較大的對象。當應用變得很是複雜時,store 對象就有可能變得至關臃腫。爲了解決以上問題,Vuex 容許咱們將 store 分割成模塊(module)。每一個模塊擁有本身的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行一樣方式的分割
user
模塊在 store
目錄下建立一個名爲 modules
的目錄並建立一個名爲 user.js
的文件,代碼以下:
const user = { // 由於模塊化了,因此解決刷新問題的代碼須要改造一下 state: sessionStorage.getItem('userState') ? JSON.parse(sessionStorage.getItem('userState')) : { user: { username: '' } }, getters: { getUser(state) { return state.user; } }, mutations: { updateUser(state, user) { state.user = user; } }, actions: { asyncUpdateUser(context, user) { context.commit('updateUser', user); } } }; export default user;
store/index.js
import Vue from 'vue' import Vuex from 'vuex' import user from './modules/user' Vue.use(Vuex); export default new Vuex.Store({ modules: { // this.$store.state.user user } });
備註:因爲組件中使用的是 getters
和 actions
處理,因此調用代碼不變
App.vue
export default { name: 'App', mounted() { window.addEventListener('unload', this.saveState); }, methods: { saveState() { // 模塊化後,調用 state 的代碼修改成 this.$store.state.user(須要定位到user這個對象) sessionStorage.setItem('userState', JSON.stringify(this.$store.state.user)); } } }