1. 程式人生 > 程式設計 >詳解uniapp的全域性變數實現方式

詳解uniapp的全域性變數實現方式

前言

本文整理了一些uniapp全域性變數的實現方式,細節知識來自於uView官網中對uniapp中的全域性變數實現,感興趣的同學可以前往uView官網搜尋vuex進行檢視

全域性變數的實現方式

一般來說在uniapp中有以下幾種方式

  • 本地儲存
  • 配置檔案
  • 掛載到 Vue.prototype
  • globalData
  • vuex

下面對這5種方式的實現進行介紹

本地儲存

永久儲存,以app為例即使該應用被關閉,該資料依然會被儲存

這是一種永久的儲存方式,類似於web的Local Storage(有關於Cookie、Token、SessionStorage、LocalStorage,會整理在另一篇文章中),當我們需要永久儲存使用者的某一資訊時會使用這種方法,但是需要注意使用這種方式需要避免對儲存資料的頻繁獲取和修改操作,因為會對效能產生一定的影響,應用宣告週期內的變數,不應該使用此種方式

這種儲存方式有 同步和非同步兩種

同步儲存

  //同步儲存
  uni.setStorageSync("key","value")
  //同步獲取
  let value = uni.getStorageSync("key")  
  console.log("我會等到上邊執行完畢後才會執行)

非同步儲存

  uni.setStorage({
   key:"key",data:"value",success:function(){
      //儲存成功的回撥
      console.log("我是非同步儲存的回撥,我會在val聲明後被執行")
    }
  })
  let val = 1//這行會先執行
  
  uni.getStorage({
   key:"key",success:function(res){
      //儲存成功的回撥
      console.log("我是非同步獲取的回撥,我會在val2聲明後被執行")
    }
  })
  let val2 = 2//這行會先執行

配置檔案

這是一種利用模組化檔案匯出實現的方式,先將變數寫在js檔案中,然後通過export default的形式匯出使用

一般來說使用這種方式實現的全域性變數,是需要在應用被使用者安裝之前到使用者解除安裝時都必須使用的變數,如向後端請求的域名,其他的情況不太適用這種方式,同時這種方式也有弊端,就是每次使用都需要引入檔案

config.js

  //如在config.js中 我們匯出了一個基礎域名
  export default{
   baseUrl:"http://www.test.com"
  }

index.js

  //通過import引入這個檔案
  import config from "../common/config.js"
  export default {
    onLoad(){
     console.log(config.baseUrl)//baseUrl:"http://www.test.com"
    }
  }

掛載到Vue.prototype

這是一種利用原型的實現方式(有關於js的原型鏈和繼承,會在整理在另一篇文章中),但是這種方式在微信小程式上會有特殊表現

注意:在微信小程式中 模板無法直接讀取展示引入的全域性變數
main.js

  //這裡的config.js參照上文已經寫好的檔案
  import config from "./common/config.js"
  //將baseUrl掛載到Vue上,此後在頁面和元件中就可以通過this.baseUrl的方式去訪問
  Vue.prototype.baseUrl = config.baseUrl

頁面中

<template>
 <!-- 微信小程式中值為undefined,其他端有效 -->
 <view>
 值為:{{this.baseUrl}}
 </view>
</template>

<script>
 export default {
 onLoad() {
    console.log(this.baseUrl)//"http://www.test.com"
 }
 }
</script>

globalData

這種方式是微信小程式特有的,小程式無法使用vuex因此出現了globalData,uniapp是小程式另一種實現因此也出現了globalData

使用globalData有以下幾點需要注意的地方:

  • globalData不是響應式的,一個檔案中對globalData的修改,不會動態的在另一個檔案中響應
  • 如果想實現globalData的"響應",你需要在onShow的生命週期中手動獲取值

對第二點進行解釋,為什麼需要在onShow裡去獲取值onLoad不行麼?

因為如果A、B頁面都引入了globalData,B在頁面內部修改了globalData的值返回A頁面,此時A頁面沒有被銷燬不會呼叫onLoad生命鉤子,只會執行onShow此時在onLoad裡去獲取globalData,那麼是不會執行的,也就無法做到響應式

App.vue

  export default{
   //需要在App.vue中去定義globalData
   globalData:{
     userName:"白居易"
    },//這裡需要注意,如果想要在App.vue中使用globalData,不能直接使用getApp().globalData.Name,因為此時getApp()未有生成
    // 1. 非V3模式,可以通過this.$scope.globalData獲取
   // 2. V3模式,可以通過getApp({allowDefault: true}).globalData獲取
    onLaunch(){
     console.log(this.$scope.globalData.userName)
    }
  }

當在App.vue中定義好globalData後我們就可以在頁面中使用了
A.vue

<template>
 <view>
 <view>
  <!-- 注意,不能在模板中直接使用 getApp().globalData.userName -->
  <<賣炭翁>>的作者是:{{author}}
 </view>
 <view>
  <u-button @click="modifyUserName">修改userName值</u-button>
 </view>
 </view>
</template>

<script>
 export default {
 data() {
  return {
  author: ''
  }
 },onShow() {
  // 每次A.vue出現在螢幕上時,都會觸發onShow,從而更新author值
  this.author = getApp().globalData.userName;
 },methods: {
  modifyUserName() {
                //此時修改了globalData的值
  getApp().globalData.userName = "詩聖";
  // 修改userName後,本頁的author依然不會自動重新整理,因為globalData不是響應式的
  // 我們仍然需要手動重新整理本頁的author值,由此可見globalData的弊端
  this.author = getApp().globalData.userName;
  }
 }
 }
</script>

Vuex的實現方式

強烈建議使用vuex的方式,在uniapp使用vuex有兩種方式,一種是基於傳統vue的方式,一種是uView封裝後的方式,下面介紹uView官網對vuexd的封裝

傳統實現方式

傳統vuex的使用方式,這裡只做簡單介紹,如果對vuex不瞭解的同學,可以去vue官網檢視官方文件

在uni.app的根目錄下建立一個store檔案,並在其中建立一個index.js檔案 內容如下

//index.js
  import Vue from "vue"
  import Vuex from "vuex"
  Vue.use(Vuex)
  const store = new Vuex.Store({
   state:{
     vuex_token:"123456"
    },//同步修改 state 中值的方法
    mutations:{
     //payload使使用者在使用mutations是傳入的引數,可以使單一值也可以是物件
     modifyToken(state,payload){
       state.vuex_token = payload.token
      }
    }
  })
  export default store

在main.js中引入

import store from '@/store';

// 將store放入Vue物件建立中
const app = new Vue({
 store,...App
})

在頁面中使用

<template>
 <view>
 <view>
  Token值為{{vuex_token}}
 </view>
 <u-button @click="btnClick">修改vuex_token</u-button>
 </view>
</template>

<script>
//這是Vue官方為了更方便使用store提供的api,詳情可以去Vue官方檢視文件
import {mapState,mapMutations} from 'vuex'; 
export default {
 computed: { 
 ...mapState(['vuex_token']) 
 },methods: { 
 ...mapMutations(['modifyToken']),btnClick() {
  // 這裡第二個引數可以普通變數或者物件,自定義的,根據mutations需求處理(不使用mapMutations的方式)
  this.$store.commit('modifyToken',{token: 'xxxyyyzzz'}
            //使用mapMutations的方式
            this.modifyToken({token: 'xxxyyyzzz'})
 }
 } 
}
</script>

uView的vuex實現方式(重點)

首說為什麼uView對vuex進行了封裝,原因有以下兩點

  • uView覺得需要在vuex中定義state和mutations,在每個需要用到vuex的地方都需要引入mapState進行解構,然後再次使用(操作繁瑣)
  • 因為vuex是將變數儲存在記憶體中的,重新整理瀏覽器就會導致vuex變數消失,一般還需要配合其他的儲存方式進行使用如LocalStorage

針對這些問題uView官方提供了自己封裝使用vuex的一套方法,這個方法結合LocalStorage、vuex,使得使用者不必再去繁瑣的呼叫vuex和考慮重新整理丟失的問題,下面我將程式碼展示,並將其思路和過過程解釋

  • 先在根目錄下建立一個index.js檔案,寫入以下內容,開頭我會先提供大致思路具體含義之後會在註釋中解釋

思路:index.js的大致思路如下

a. 為了解決vuex重新整理丟失無法永久儲存資料的問題,建立了一個lifeData物件,這個物件會通過函式,將其儲存在LocalStorage中,以達到永久儲存的效果,此時我只需要將vuex中需要永久儲存的資料,以key、value的形式儲存在這個物件中就可以了

b. 為了解決每次使用vuex都需要使用mutations中的函式去操作對應的stroe中的變數,封裝了$uStore這一個方法去操作所有的store中的變數,當然只進行了簡單的複製操作,對於更拓展的功能,使用者可以自己在mutations中去封裝函式進行拓展

c. 封裝一個saveStateKeys陣列,這個陣列的資料會在app啟動時就會被取出,因此我們可以把一些需要app啟動時就獲取的資料放在其中,如應用中上次使用者已經登陸的資訊,實際上saveStateKeys和lifeData是配合使用的,只有存在saveStateKeys中的變數,才會在儲存時被儲存在lifeData中以達到永久的儲存,其他的就和普通vuex儲存方式一樣,對於這點我們可以在下述程式碼中看到

//引入Vuex、vue 使用Vuex,這一步和一般使用vuex沒有區別
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

//建立一個變數,這個變數用於儲存需要永久儲存的資料
let lifeData = {};

try{
  // 嘗試獲取本地是否存在lifeData變數,第一次啟動APP時是不存在的
  lifeData = uni.getStorageSync('lifeData');
}catch(e){
 
}

// 需要永久儲存,且下次APP啟動需要取出的,在state中的變數名
let saveStateKeys = ['vuex_user','vuex_token'];

// 儲存變數到本地儲存中(達到重新整理/重啟(app不存在重新整理,app只會重啟)不丟失)
const saveLifeData = function(key,value){
 // 判斷變數名是否在需要儲存的陣列中
  //這一條就是在判斷如果變數名儲存在saveStateKeys中,那麼就將其儲存在lifeData中達到永久儲存,否則就和一般vuex的儲存方式一樣
 if(saveStateKeys.indexOf(key) != -1) {
 // 獲取本地儲存的lifeData物件,將變數新增到物件中
 let tmp = uni.getStorageSync('lifeData');
 // 第一次開啟APP,不存在lifeData變數,故放一個{}空物件
 tmp = tmp ? tmp : {};
 tmp[key] = value;
 // 執行這一步後,所有需要儲存的變數,都掛載在本地的lifeData物件中
 uni.setStorageSync('lifeData',tmp);
 }
}
const store = new Vuex.Store({
 // 下面這些值僅為示例,使用過程中請刪除
 state: {
 // 如果上面從本地獲取的lifeData物件下有對應的屬性,就賦值給state中對應的變數
 // 加上vuex_字首,是防止變數名衝突,也讓人一目瞭然 
 // 被永久儲存的資料會從lifeData中去獲取,因為lifeData已經儲存在了本地中
 vuex_user: lifeData.vuex_user ? lifeData.vuex_user : {name: '明月'},vuex_token: lifeData.vuex_token ? lifeData.vuex_token : '',// 如果vuex_version無需儲存到本地永久儲存,無需lifeData.vuex_version方式
 vuex_version: '1.0.1',},mutations: {
 $uStore(state,payload) {
            //payload就是後來呼叫的this.$u.vuex時傳入的物件
            //如this.$u.vuex("user.info.score","jack") payload = {name:"user.info.score",value:"jack"}
  // 判斷是否多層級呼叫,state中為物件存在的情況,諸如user.info.score = 1
  let nameArr = payload.name.split('.');//[user,info,score]
  let saveKey = '';
  let len = nameArr.length;
  if(nameArr.length >= 2) {
  let obj = state[nameArr[0]];
  for(let i = 1; i < len - 1; i ++) {
   obj = obj[nameArr[i]];// 此時obj就是user.info,當然此時他還是一個空資料
  }
                //nameArr[len-1]就是score,obj[nameArr[len - 1]]相當於 user.info.score
  obj[nameArr[len - 1]] = payload.value;
  saveKey = nameArr[0];
  } else {
  // 單層級變數,在state就是一個普通變數的情況
  state[payload.name] = payload.value;
  saveKey = payload.name;
  }
  // 儲存變數到本地,見頂部函式定義
  saveLifeData(saveKey,state[saveKey])
 }
 }
})
export default store

在同目錄下建立 mixin.js檔案

思路:
a. 為了能夠在每個頁面都能通過this.的方式使用變數,我們需要將mapState通過Vue mixin的方式進行全域性混入
b. 為了能夠在每個頁面都能輕鬆的呼叫vuex中的mutations裡的方法,我們需要一個方法能夠幫我們去呼叫uStore,而不是每次都通過commit的方式,因此uView還混入了另一個方法$u.vuex

ps: minxi(混入)是Vue提供的一種實現全域性功能的一個api,混入有多種方式這裡使用了全域性混入,如果對於混入不是很瞭解可以去Vue官網檢視相關文件

//mixin.js
import { mapState } from 'vuex'
import store from "@/store"

// 嘗試將使用者在根目錄中的store/index.js的vuex的state變數,全部載入到全域性變數中
let $uStoreKey = [];
try{
 $uStoreKey = store.state ? Object.keys(store.state) : [];
}catch(e){
 
}

module.exports = {
 created() {
 // 將vuex方法掛到this.$u上
 // 使用方法為:如果要修改vuex的state中的user.name變數為"史詩" => this.$u.vuex('user.name','史詩')
 // 如果要修改vuex的state的version變數為1.0.1 => this.$u.vuex('version','1.0.1')
 this.$u.vuex = (name,value) => {
  this.$store.commit('$uStore',{
  name,value //這裡有沒有回憶起來$uStore傳入的payload haha 
  })
 }
 },computed: {
 // 將vuex的state中的所有變數,解構到全域性混入的mixin中
 ...mapState($uStoreKey)
 }
}

開始全域性混入,在main.js中引入 mixin.js檔案進行混入

//main.js
let vuexStore = require("@/store/$u.mixin.js");
Vue.mixin(vuexStore);

將store放到Vue例項中

//main.js
import store from '@/store';

// 將store放入Vue物件建立中
const app = new Vue({
 store,...App
})

以上就是uView官方對vuex的封裝,在app開發中使用這種封裝後的vuex很便捷,同時自身也可以根據需要在@/stote/index.js中去拓展自己的方法

結語

以上就是uniapp全域性變數的不同實現方式,具體使用哪一種需要在實際開發中根據實際選擇,個人感覺uView對vuex的封裝,對於初入前端我而言有著很高參考價值,因此特別整理出來留存分享。

到此這篇關於詳解uniapp的全域性變數實現方式的文章就介紹到這了,更多相關uniapp 全域性變數內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!