vue項(xiàng)目基礎(chǔ)用法教程(二)

創(chuàng)建項(xiàng)目

vue-cli腳手架生成項(xiàng)目

vue create 項(xiàng)目名稱

配置參考

vue-router配置

vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,適合用于構(gòu)建單頁(yè)面應(yīng)用。
我們可以訪問(wèn)其官方網(wǎng)站對(duì)其進(jìn)行學(xué)習(xí): https://router.vuejs.org/zh/

1. 安裝vue-router(創(chuàng)建項(xiàng)目時(shí)若已勾選vue-router請(qǐng)忽略)

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è)應(yīng)用的基路徑
    base: '',
    // 路由模式 hash || history
    mode: 'hash',
    // 切換路由滾動(dòng)條置頂
    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>我是首頁(yè)標(biāo)題</h2>
      <p>我是首頁(yè)內(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í)例,但是我們并沒(méi)有配置路由間的映射關(guān)系

import Vue from 'vue'
import VueRouter from 'vue-router'
 
 
Vue.use(VueRouter)
 
const routes =  [
  {
    //默認(rèn)首頁(yè)
    path: '/',
    redirect: '/home'
  },
  {
    // 路由地址
    path: '/home',
    // 路由名稱
    name:'Home', 
    // 采用異步引入方式
    component: () => import('@/views/home'),
    // 存儲(chǔ)一些自定義參數(shù)
    meta:{
        title:'首頁(yè)',
        hidden: false // menu是否顯示此路由
    }
  },
  {
    path: '/about',
    name:'About',
    component: () => import('@/views/about'),
    meta:{
        title:'關(guān)于我們',
    }
  }
]
 
// 創(chuàng)建路由實(shí)例
const router = new VueRouter({
    // 配置單頁(yè)應(yīng)用的基路徑
    base: '',
    // 路由模式 hash || history
    mode: 'hash',
    // 切換路由滾動(dòng)條置頂
    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)綁定動(dòng)態(tài)的 路由 和 參數(shù)
        根據(jù)路由路徑(/home)跳轉(zhuǎn) <router-link :to="{path: '/home', query:{id: 'abc'}}">點(diǎn)擊查看子頁(yè)面</router-link>
        根據(jù)路由名稱(About)跳轉(zhuǎn) <router-link :to="{name: 'About', params:{id: 'abc'}}">點(diǎn)擊查看子頁(yè)面</router-link>
        另外還可以直接在path后面+?拼接key=value&key=value的方式直接傳參,例<router-link to="/home?id=xxx&&name=xxxx">首頁(yè)</router-link>
        備注:query和params為兩種不同的傳參方式,query會(huì)拼接在url地址后面刷新不會(huì)丟失,params在url上不會(huì)顯示,刷新會(huì)丟失。
    --> 
    <router-link to="/home">首頁(yè)</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)綁定動(dòng)態(tài)的 路由 和 參數(shù)
根據(jù)路由路徑(/home)跳轉(zhuǎn) <router-link :to="{path: '/home', query:{id: 'abc'}}">點(diǎn)擊查看子頁(yè)面</router-link>
根據(jù)路由名稱(detail)跳轉(zhuǎn) <router-link :to="{name: 'detail', params:{id: 'abc'}}">點(diǎn)擊查看子頁(yè)面</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ù)不會(huì)出現(xiàn)在url的路徑上面,但是刷新頁(yè)面時(shí)param里面的數(shù)據(jù)會(huì)消失
2、query傳參時(shí),參數(shù)出現(xiàn)在url的路徑上面,刷新頁(yè)面時(shí)query里面的數(shù)據(jù)不變

8. back && go 返回上一頁(yè)

go(-1): 原頁(yè)面表單中的內(nèi)容會(huì)丟失

this.$router.go(-1):后退+刷新;
this.$router.go(0):刷新;
this.$router.go(1) :前進(jìn)

back(): 原頁(yè)表表單中的內(nèi)容會(huì)保留

this.$router.back():后退 ;
this.$router.back(0) 刷新;
this.$router.back(1):前進(jìn)

9.keep-alive的使用

keep-alive是vue內(nèi)置的一個(gè)組件,而這個(gè)組件的作用就是能夠緩存不活動(dòng)的組件,我們能夠知道,一般情況下,組件進(jìn)行切換的時(shí)候,默認(rèn)會(huì)進(jìn)行銷毀,如果有需求,某個(gè)組件切換后不進(jìn)行銷毀,而是保存之前的狀態(tài),那么就可以利用keep-alive來(lái)實(shí)現(xiàn)

  1. 利用meta標(biāo)簽
    首先在路由中的meta標(biāo)簽中記錄keepAlive的屬性為true
...
{
    path: '/about',
    name:'About',
    component: () => import('@/views/about'),
    meta:{
        title:'關(guān)于我們',
        keepAlive:true // 代表改頁(yè)面需要緩存
    }
  }
...
  1. 在需要緩存的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>
  1. 使用include、exclude屬性和beforeRouteEnter鉤子函數(shù)

include是需要緩存的組件;
exclude是除了某些組件都緩存;
include 和 exclude
屬性允許組件有條件地緩存。二者都可以用逗號(hào)分隔字符串、正則表達(dá)式或一個(gè)數(shù)組來(lái)表示:
將需要緩存的組件加在include屬性里
max 表示最大緩存路由個(gè)數(shù)

<keep-alive :include="['home','about']">
      <router-view></router-view>
</keep-alive>

備注:一般情況設(shè)置tab路由切換,訪問(wèn)一個(gè)路由push到訪問(wèn)歷史訪問(wèn)數(shù)組中,過(guò)濾需要緩存的路由push到include

10. 路由鉤子函數(shù)

  1. vue router.beforeEach(全局前置守衛(wèi))

to: (Route路由對(duì)象) 即將要進(jìn)入的目標(biāo) 路由對(duì)象 to對(duì)象下面的屬性: path params query hash fullPath matched name meta
from: (Route路由對(duì)象) 當(dāng)前導(dǎo)航正要離開的路由
next: (Function函數(shù)) 一定要調(diào)用該方法來(lái) resolve 這個(gè)鉤子。 調(diào)用方法:next(參數(shù)或者空) ***必須調(diào)用

應(yīng)用場(chǎng)景:判斷需要登錄的頁(yè)面進(jìn)行攔截

router.beforeEach((to, from, next) => {
    if (to.meta.requireAuth) {
        //判斷該路由是否需要登錄權(quán)限
        if (cookies('token')) {
            //通過(guò)封裝好的cookies讀取token,如果存在,name接下一步如果不存在,那跳轉(zhuǎn)回登錄頁(yè)
            next()//不要在next里面加"path:/",會(huì)陷入死循環(huán)
        }
        else {
            next({
                path: '/login',
                query:  { redirect:to.fullPath } //將跳轉(zhuǎn)的路由path作為參數(shù),登錄成功后跳轉(zhuǎn)到該路由
            })
        }
    }
    else {
        next()
    }
})
  1. vue router.afterEach(全局后置守衛(wèi))

router.beforeEach 是頁(yè)面加載之前,相反router.afterEach是頁(yè)面加載之后

  1. 組件內(nèi)路由守衛(wèi)

beforeRouteEnter(進(jìn)入前)、beforeRouteUpdate(刷新)、beforeRouteLeave(離開時(shí)) 類似于組件內(nèi)生命周期函數(shù)。

應(yīng)用場(chǎng)景:清除當(dāng)前組件中的定時(shí)器

beforeRouteLeave (to, from, next) {
  window.clearInterval(this.timer) //清楚定時(shí)器
  next()
}

應(yīng)用場(chǎng)景:當(dāng)頁(yè)面中有未關(guān)閉的窗口, 或未保存的內(nèi)容時(shí), 阻止頁(yè)面跳轉(zhuǎn)

beforeRouteLeave (to, from, next) {
 //判斷是否彈出框的狀態(tài)和保存信息與否
 if (this.dialogVisibility === true) {
    this.dialogVisibility = false //關(guān)閉彈出框
    next(false) //回到當(dāng)前頁(yè)面, 阻止頁(yè)面跳轉(zhuǎn)
  }else if(this.saveMessage === false) {
    alert('請(qǐng)保存信息后退出!') //彈出警告
    next(false) //回到當(dāng)前頁(yè)面, 阻止頁(yè)面跳轉(zhuǎn)
  }else {
    next() //否則允許跳轉(zhuǎn)
  }

應(yīng)用場(chǎng)景:保存相關(guān)內(nèi)容到Vuex中或Session中

beforeRouteLeave (to, from, next) {
    localStorage.setItem(name, content); //保存到localStorage中
    next()
}
  1. 實(shí)現(xiàn)緩存界面保存滾動(dòng)位置
    簡(jiǎn)單方法
    router.js
// keepAlive是否需要保持頁(yè)面,scrollTop記錄頁(yè)面的滾動(dòng)位置
...
meta: {
  keepAlive: true,
  scrollTop: 0, // 用于保存滾動(dòng)條位置
}
...

vue文件中

export default {
    data(){
      scrollTop: 0, // 儲(chǔ)存滾動(dòng)位置
    },
    activated() {
      // 進(jìn)入該組件后讀取數(shù)據(jù)變量設(shè)置滾動(dòng)位置
      // 注意, 此處由頁(yè)面是否具有 DTD (如: `<!DOCTYPE html>`), 
      // 決定具體選擇, 詳見參考資料
      document.documentElement.scrollTop = this.scrollTop;
      // document.body.scrollTop = this.scrollTop;
    },
    beforeRouteLeave(to, from, next) {
      // 離開組件時(shí)保存滾動(dòng)位置
      // 注意, 此時(shí)需調(diào)用路由守衛(wèi)`beforeRouterLeave`而非生命周期鉤子`deactivated`
      // 因?yàn)? 此時(shí)利用`deactivated`獲取的 DOM 信息已經(jīng)是新頁(yè)面得了
      this.scrollTop = document.documentElement.scrollTop;
      next();
    },
  }

router.js 全局保存方法

// keepAlive是否需要保持頁(yè)面,scrollTop記錄頁(yè)面的滾動(dòng)位置
...
meta: {
  keepAlive: true,
  scrollTop: 0, // 用于保存滾動(dòng)條位置
}
...

router.beforeEach((to: Route, from: Route, next: () => void) => {  
  if (from.meta.keepAlive) {
  // 同意使用id = conetent外層包裹,且僅記錄外層滾動(dòng)條
  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)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化。

1. 安裝vuex

npm install vuex --save

2. 創(chuàng)建實(shí)例

為了項(xiàng)目格式便于維護(hù)和相對(duì)規(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文件

  1. state 初始化全局可訪問(wèn)的數(shù)據(jù)
const state = () => ({
    username:''
})

vue頁(yè)面中可使用 this.store.state.user.username 獲取參數(shù)

  1. getters 可以實(shí)時(shí)監(jiān)聽state值的變化
const getters = {
     username: (state) => state.username,
}

vue頁(yè)面中可使用 this.store.getters['user/username'] 獲取參數(shù)
或者

import { mapGetters } from 'vuex'
 export default {
  computed: {
    ...mapGetters({
      username: 'user/username',
    }),
  },
}
  1. mutations 用于修改state值,一般都是action中調(diào)用
const mutations = {
    setUsername(state, username) {
        state.username = username
    },
}

vue頁(yè)面中可使用 this.store.getters['user/username'] 獲取參數(shù)

  1. 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頁(yè)面中調(diào)用 this.$store.dispatch('user/getUserInfo')

  1. 最后導(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用法

  1. vue頁(yè)面中通過(guò)v-for進(jìn)行數(shù)據(jù)渲染,如果層次太多,有時(shí)候數(shù)據(jù)發(fā)生改變但是頁(yè)面上看到的效果是毫無(wú)變化。render函數(shù)沒(méi)有自動(dòng)更新,可以通過(guò)this.$forceUpdate()手動(dòng)刷新.

原因:對(duì)象添加屬性未使用this.set()賦值 解決:使用this.forceUpdate();

vm.$forceUpdate()

迫使Vue實(shí)例重新渲染,但僅影響實(shí)例本身和插入插槽內(nèi)容的子組件。

vm.$set(target, propertyName/index, value)

官方推薦我們給對(duì)象中添加一個(gè)屬性的時(shí)候用 this.$set(target, propertyName/index, value)

  1. 我們更改了某個(gè)dom元素內(nèi)部的文本,而這時(shí)候我們想直接打印出這個(gè)被改變后的文本時(shí)需要dom更新之后才會(huì)實(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)還沒(méi)有渲染完成。
    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)元素通過(guò)ref綁定后,可以通過(guò) 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)用了我的方法')
      }
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容