創(chuàng)建項(xiàng)目
vue-cli腳手架生成項(xiàng)目
vue create 項(xiàng)目名稱
vue-router配置
vue-router是Vue.js官方的路由插件歼跟,它和vue.js是深度集成的沼填,適合用于構(gòu)建單頁面應(yīng)用。
我們可以訪問其官方網(wǎng)站對其進(jìn)行學(xué)習(xí): https://router.vuejs.org/zh/
1. 安裝vue-router(創(chuàng)建項(xiàng)目時(shí)若已勾選vue-router請忽略)
npm install vue-router --save
2. 創(chuàng)建路由實(shí)例
一般在src目錄下創(chuàng)建router文件夾再創(chuàng)建index.js文件
import Vue from 'vue'
import VueRouter from 'vue-router'
// 注入插件
Vue.use(VueRouter)
// 定義公共路由
const routes = [
]
// 創(chuàng)建路由實(shí)例
const router = new VueRouter({
// 配置單頁應(yīng)用的基路徑
base: '',
// 路由模式 hash || history
mode: 'hash',
// 切換路由滾動條置頂
scrollBehavior: () => ({
y: 0,
}),
// 路由數(shù)組
routes: routes
})
// 導(dǎo)出實(shí)例
export default router
3. 掛載到vue實(shí)例中
在main.js中引入router
import Vue from 'vue'
import App from './App.vue'
//導(dǎo)入router
import router from './router'
Vue.config.productionTip = false
new Vue({
router, //掛載
render: h => h(App)
}).$mount('#app')
4. 創(chuàng)建路由組件
在views目錄下創(chuàng)建about.vue和home.vue兩個(gè)組件
home.vue
<template>
<div>
<h2>我是首頁標(biāo)題</h2>
<p>我是首頁內(nèi)容</p>
</div>
</template>
<script>
export default {
name: 'home'
}
</script>
<style>
</style>
about.vue
<template>
<div>
<h2>我是關(guān)于標(biāo)題</h2>
<p>我是關(guān)于內(nèi)容</p>
</div>
</template>
<script>
export default {
name: 'about'
}
</script>
<style>
</style>
5. 配置組件和路徑的映射關(guān)系
創(chuàng)建路由實(shí)例的index.js中創(chuàng)建了router實(shí)例瞄摊,但是我們并沒有配置路由間的映射關(guān)系
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
//默認(rèn)首頁
path: '/',
redirect: '/home'
},
{
// 路由地址
path: '/home',
// 路由名稱
name:'Home',
// 采用異步引入方式
component: () => import('@/views/home')焊傅,
// 存儲一些自定義參數(shù)
meta:{
title:'首頁',
hidden: false // menu是否顯示此路由
}
},
{
path: '/about',
name:'About',
component: () => import('@/views/about')鹏往,
meta:{
title:'關(guān)于我們',
}
}
]
// 創(chuàng)建路由實(shí)例
const router = new VueRouter({
// 配置單頁應(yīng)用的基路徑
base: '',
// 路由模式 hash || history
mode: 'hash',
// 切換路由滾動條置頂
scrollBehavior: () => ({
y: 0,
}),
// 路由數(shù)組
routes: routes
})
// 導(dǎo)出router實(shí)例
export default router
6. 使用路由
在App.vue中使用路由
<template>
<div id="app">
<!--
1. :to="" 可以實(shí)現(xiàn)綁定動態(tài)的 路由 和 參數(shù)
根據(jù)路由路徑(/home)跳轉(zhuǎn) <router-link :to="{path: '/home', query:{id: 'abc'}}">點(diǎn)擊查看子頁面</router-link>
根據(jù)路由名稱(About)跳轉(zhuǎn) <router-link :to="{name: 'About', params:{id: 'abc'}}">點(diǎn)擊查看子頁面</router-link>
另外還可以直接在path后面+?拼接key=value&key=value的方式直接傳參,例<router-link to="/home?id=xxx&&name=xxxx">首頁</router-link>
備注:query和params為兩種不同的傳參方式粱侣,query會拼接在url地址后面刷新不會丟失饭玲,params在url上不會顯示侥祭,刷新會丟失。
-->
<router-link to="/home">首頁</router-link>
<router-link to="/about">關(guān)于</router-link>
<!-- 路由出口 -->
<!-- 路由匹配到的組件將渲染在這里 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
methods:{
toHome(){
}
}
}
</script>
7. 路由跳轉(zhuǎn)方式
聲明式
:to="" 可以實(shí)現(xiàn)綁定動態(tài)的 路由 和 參數(shù)
根據(jù)路由路徑(/home)跳轉(zhuǎn) <router-link :to="{path: '/home', query:{id: 'abc'}}">點(diǎn)擊查看子頁面</router-link>
根據(jù)路由名稱(detail)跳轉(zhuǎn) <router-link :to="{name: 'detail', params:{id: 'abc'}}">點(diǎn)擊查看子頁面</router-link>
編程式
this.$router.push({path: '/home',query:{id: 'abc'}})
this.$router.push({path: '/home',params:{id: 'abc'}})
params 和 query 傳參的區(qū)別
1茄厘、params傳參時(shí)矮冬,參數(shù)不會出現(xiàn)在url的路徑上面,但是刷新頁面時(shí)param里面的數(shù)據(jù)會消失
2次哈、query傳參時(shí)欢伏,參數(shù)出現(xiàn)在url的路徑上面,刷新頁面時(shí)query里面的數(shù)據(jù)不變
8. back && go 返回上一頁
go(-1): 原頁面表單中的內(nèi)容會丟失
this.$router.go(-1):后退+刷新;
this.$router.go(0):刷新径筏;
this.$router.go(1) :前進(jìn)
back(): 原頁表表單中的內(nèi)容會保留
this.$router.back():后退 葛假;
this.$router.back(0) 刷新;
this.$router.back(1):前進(jìn)
9.keep-alive的使用
keep-alive是vue內(nèi)置的一個(gè)組件滋恬,而這個(gè)組件的作用就是能夠緩存不活動的組件聊训,我們能夠知道,一般情況下恢氯,組件進(jìn)行切換的時(shí)候带斑,默認(rèn)會進(jìn)行銷毀,如果有需求勋拟,某個(gè)組件切換后不進(jìn)行銷毀勋磕,而是保存之前的狀態(tài),那么就可以利用keep-alive來實(shí)現(xiàn)
- 利用meta標(biāo)簽
首先在路由中的meta標(biāo)簽中記錄keepAlive的屬性為true
...
{
path: '/about',
name:'About',
component: () => import('@/views/about'),
meta:{
title:'關(guān)于我們',
keepAlive:true // 代表改頁面需要緩存
}
}
...
- 在需要緩存的router-view組件上包裹keep-alive組件
<keep-alive>
<router-view v-if='$route.meta.keepAlive'></router-view>
</keep-alive>
<router-view v-if='!$route.meta.keepAlive'></router-view>
- 使用include敢靡、exclude屬性和beforeRouteEnter鉤子函數(shù)
include是需要緩存的組件挂滓;
exclude是除了某些組件都緩存;
include 和 exclude
屬性允許組件有條件地緩存啸胧。二者都可以用逗號分隔字符串赶站、正則表達(dá)式或一個(gè)數(shù)組來表示:
將需要緩存的組件加在include屬性里
max 表示最大緩存路由個(gè)數(shù)
<keep-alive :include="['home','about']">
<router-view></router-view>
</keep-alive>
備注:一般情況設(shè)置tab路由切換,訪問一個(gè)路由push到訪問歷史訪問數(shù)組中纺念,過濾需要緩存的路由push到include
10. 路由鉤子函數(shù)
- vue router.beforeEach(全局前置守衛(wèi))
to: (Route路由對象) 即將要進(jìn)入的目標(biāo) 路由對象 to對象下面的屬性: path params query hash fullPath matched name meta
from: (Route路由對象) 當(dāng)前導(dǎo)航正要離開的路由
next: (Function函數(shù)) 一定要調(diào)用該方法來 resolve 這個(gè)鉤子贝椿。 調(diào)用方法:next(參數(shù)或者空) ***必須調(diào)用
應(yīng)用場景:判斷需要登錄的頁面進(jìn)行攔截
router.beforeEach((to, from, next) => {
if (to.meta.requireAuth) {
//判斷該路由是否需要登錄權(quán)限
if (cookies('token')) {
//通過封裝好的cookies讀取token,如果存在陷谱,name接下一步如果不存在烙博,那跳轉(zhuǎn)回登錄頁
next()//不要在next里面加"path:/",會陷入死循環(huán)
}
else {
next({
path: '/login',
query: { redirect:to.fullPath } //將跳轉(zhuǎn)的路由path作為參數(shù),登錄成功后跳轉(zhuǎn)到該路由
})
}
}
else {
next()
}
})
- vue router.afterEach(全局后置守衛(wèi))
router.beforeEach 是頁面加載之前,相反router.afterEach是頁面加載之后
- 組件內(nèi)路由守衛(wèi)
beforeRouteEnter(進(jìn)入前)习勤、beforeRouteUpdate(刷新)踪栋、beforeRouteLeave(離開時(shí)) 類似于組件內(nèi)生命周期函數(shù)。
應(yīng)用場景:清除當(dāng)前組件中的定時(shí)器
beforeRouteLeave (to, from, next) {
window.clearInterval(this.timer) //清楚定時(shí)器
next()
}
應(yīng)用場景:當(dāng)頁面中有未關(guān)閉的窗口, 或未保存的內(nèi)容時(shí), 阻止頁面跳轉(zhuǎn)
beforeRouteLeave (to, from, next) {
//判斷是否彈出框的狀態(tài)和保存信息與否
if (this.dialogVisibility === true) {
this.dialogVisibility = false //關(guān)閉彈出框
next(false) //回到當(dāng)前頁面, 阻止頁面跳轉(zhuǎn)
}else if(this.saveMessage === false) {
alert('請保存信息后退出!') //彈出警告
next(false) //回到當(dāng)前頁面, 阻止頁面跳轉(zhuǎn)
}else {
next() //否則允許跳轉(zhuǎn)
}
應(yīng)用場景:保存相關(guān)內(nèi)容到Vuex中或Session中
beforeRouteLeave (to, from, next) {
localStorage.setItem(name, content); //保存到localStorage中
next()
}
- 實(shí)現(xiàn)緩存界面保存滾動位置
簡單方法
router.js
// keepAlive是否需要保持頁面图毕,scrollTop記錄頁面的滾動位置
...
meta: {
keepAlive: true,
scrollTop: 0, // 用于保存滾動條位置
}
...
vue文件中
export default {
data(){
scrollTop: 0, // 儲存滾動位置
},
activated() {
// 進(jìn)入該組件后讀取數(shù)據(jù)變量設(shè)置滾動位置
// 注意, 此處由頁面是否具有 DTD (如: `<!DOCTYPE html>`),
// 決定具體選擇, 詳見參考資料
document.documentElement.scrollTop = this.scrollTop;
// document.body.scrollTop = this.scrollTop;
},
beforeRouteLeave(to, from, next) {
// 離開組件時(shí)保存滾動位置
// 注意, 此時(shí)需調(diào)用路由守衛(wèi)`beforeRouterLeave`而非生命周期鉤子`deactivated`
// 因?yàn)? 此時(shí)利用`deactivated`獲取的 DOM 信息已經(jīng)是新頁面得了
this.scrollTop = document.documentElement.scrollTop;
next();
},
}
router.js 全局保存方法
// keepAlive是否需要保持頁面夷都,scrollTop記錄頁面的滾動位置
...
meta: {
keepAlive: true,
scrollTop: 0, // 用于保存滾動條位置
}
...
router.beforeEach((to: Route, from: Route, next: () => void) => {
if (from.meta.keepAlive) {
// 同意使用id = conetent外層包裹,且僅記錄外層滾動條
const $content = document.querySelector('#content');
const scrollTop = $content ? $content.scrollTop : 0;
from.meta.scrollTop = scrollTop;
}
next();
});
Vuex
Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的
狀態(tài)管理模式
予颤。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài)囤官,并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。
1. 安裝vuex
npm install vuex --save
2. 創(chuàng)建實(shí)例
為了項(xiàng)目格式便于維護(hù)和相對規(guī)范一點(diǎn)蛤虐,目錄下建立一個(gè) store 文件夾党饮,并且在下面建立一個(gè) index.js 文件和 modules文件夾
index.js
用于導(dǎo)入modules文件夾所有文件
import Vue from 'vue'
import Vuex from 'vuex'
// 注入插件
Vue.use(Vuex)
const files = require.context('./modules', false, /\.js$/)
const modules = {}
files.keys().forEach((key) => {
modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default
})
Object.keys(modules).forEach((key) => {
modules[key]['namespaced'] = true
})
const store = new Vuex.Store({
modules,
})
導(dǎo)出實(shí)例
export default store
3. 掛載到vue實(shí)例中
在main.js中引入router
import Vue from 'vue'
import App from './App.vue'
//導(dǎo)入router
import router from './router'
//導(dǎo)入vuex
import store from './store'
Vue.config.productionTip = false
new Vue({
router, //掛載
store, //掛載
render: h => h(App)
}).$mount('#app')
4.vuex store
在modules目錄下創(chuàng)建user.js文件
- state 初始化全局可訪問的數(shù)據(jù)
const state = () => ({
username:''
})
vue頁面中可使用 this.store.state.user.username 獲取參數(shù)
- getters 可以實(shí)時(shí)監(jiān)聽state值的變化
const getters = {
username: (state) => state.username,
}
vue頁面中可使用 this.store.getters['user/username'] 獲取參數(shù)
或者
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters({
username: 'user/username',
}),
},
}
- mutations 用于修改state值,一般都是action中調(diào)用
const mutations = {
setUsername(state, username) {
state.username = username
},
}
vue頁面中可使用 this.store.getters['user/username'] 獲取參數(shù)
- Action 提交的是 mutation驳庭,而不是直接變更狀態(tài)刑顺。
Action 可以包含任意異步操作。
const actions = {
async getUserInfo({ commit, state }) {
//調(diào)取用戶信息接口
const { data } = await getUserInfo(state.accessToken)
if (!data) {
// 失敗操作
return false
}
let { username } = data
// 修改用戶名的值
commit('setUsername', username);
},
}
vue頁面中調(diào)用 this.$store.dispatch('user/getUserInfo')
- 最后導(dǎo)出方法
export default { state, getters, mutations, actions }
user.js 完整代碼
// 引入封裝的接口
import { getUserInfo } from "@/api/user.js"
const state = () => ({
username:''
})
const getters = {
username: (state) => state.username,
}
const mutations = {
setUsername(state, username) {
state.username = username
},
}
const actions = {
async getUserInfo({ commit, state }) {
//調(diào)取用戶信息接口
const { data } = await getUserInfo(state.accessToken)
if (!data) {
// 失敗操作
return false
}
let { username } = data
// 修改用戶名的值
commit('setUsername', username);
},
}
export default { state, getters, mutations, actions }
補(bǔ)充Vue用法
- vue頁面中通過v-for進(jìn)行數(shù)據(jù)渲染饲常,如果層次太多蹲堂,有時(shí)候數(shù)據(jù)發(fā)生改變但是頁面上看到的效果是毫無變化。render函數(shù)沒有自動更新贝淤,可以通過this.$forceUpdate()手動刷新.
原因:對象添加屬性未使用this.
forceUpdate();
vm.$forceUpdate()
迫使Vue實(shí)例重新渲染柒竞,但僅影響實(shí)例本身和插入插槽內(nèi)容的子組件。
vm.$set(target, propertyName/index, value)
官方推薦我們給對象中添加一個(gè)屬性的時(shí)候用 this.$set(target, propertyName/index, value)
- 我們更改了某個(gè)dom元素內(nèi)部的文本播聪,而這時(shí)候我們想直接打印出這個(gè)被改變后的文本時(shí)需要dom更新之后才會實(shí)現(xiàn)的朽基,也就好比我們將打印輸出的代碼放在setTimeout(fn, 0)中,此時(shí)可以使用this.$nextTick()
vm.$nextTick()
this.$nextTick()將回調(diào)延遲到下次 DOM 更新循環(huán)之后執(zhí)行。在修改數(shù)據(jù)之后立即使用它离陶,然后等待 DOM 更新稼虎。
示例1:
<template>
<section>
<div ref="hello">
<h1>Hello World ~</h1>
</div>
</section>
</template>
<script>
export default {
methods: {
get() {
}
},
// created生命周期進(jìn)行時(shí)Dom節(jié)點(diǎn)還沒有渲染完成。
created() {
console.log(this.$refs['hello']); // undefined
this.$nextTick(() => {
console.log(this.$refs['hello']);// <div>...</div>
});
},
// mounted生命周期進(jìn)行時(shí)Dom節(jié)點(diǎn)已經(jīng)渲染完成招刨。
mounted() {
console.log(this.$refs['hello']);// <div>...</div>
this.$nextTick(() => {
console.log(this.$refs['hello']);// <div>...</div>
});
}
}
</script>
示例2:
<template>
<section>
<h1 ref="hello">{{ value }}</h1>
<el-button type="danger" @click="get">點(diǎn)擊</el-button>
</section>
</template>
<script>
export default {
data() {
return {
value: 'Hello World ~'
};
},
methods: {
get() {
this.value = '你好啊';
console.log(this.$refs['hello'].innerText); // Hello World ~
this.$nextTick(() => {
console.log(this.$refs['hello'].innerText); // 你好啊
});
}
},
mounted() {
},
created() {
}
}
</script>
vm.$refs
當(dāng)元素通過ref綁定后渡蜻,可以通過 this.$refs.refName 獲取這個(gè)dom節(jié)點(diǎn)。
示例:
<template>
<ul>
<li v-for="(item,index) in list" :key="index" ref="list">
{{item}}
</li>
</ul>
</template>
<script>
export default {
data(){
return{
list:[1,2,4,5,6,7,8]
}
},
mounted(){
console.log(this.$refs.list)
//添加隨機(jī)顏色
this.$refs.list.forEach((v)=>{
v.style.color ='#' + Math.floor(Math.random()*1000000)
})
}
}
</script>
ref 加在子組件上计济,用 this.$refs.name茸苇,獲取到的是組件實(shí)例,可以使用組件的所有方法沦寂。
示例:
<!-父組件--->
<template>
<div>
<child ref="child" ></child>
</div>
</template>
<script>
import child from './child'
export default {
components:{
child
}
mounted(){
this.$refs.child.getData() // 調(diào)用
}
}
<!-子組件--->
<template>
<div></div>
</template>
<script>
export default {
methods:{
getData(){
console.log('父組件調(diào)用了我的方法')
}
}
}