详解uniapp的全局变量实现方式


Posted in Javascript onJanuary 11, 2021

前言

本文整理了一些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 全局变量内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JS刷新框架外页面七种实现代码
Feb 18 Javascript
Blocksit插件实现瀑布流数据无限( 异步)加载
Jun 20 Javascript
QQ登录背景闪动效果附效果演示源码下载
Sep 22 Javascript
基于javascript显示当前时间以及倒计时功能
Mar 18 Javascript
AngularJS实现textarea记录只能输入规定数量的字符并显示
Apr 26 Javascript
Bootstrap组件(一)之菜单
May 11 Javascript
老生常谈JavaScript中的this关键字
Oct 01 Javascript
BootStrap+Mybatis框架下实现表单提交数据重复验证
Mar 23 Javascript
解决Mac安装thrift因bison报错的问题
May 17 Javascript
谈谈JavaScript中的垃圾回收机制
Sep 17 Javascript
JavaScript检测是否开启了控制台(F12调试工具)
Oct 02 Javascript
JavaScript常用进制转换及位运算实例解析
Oct 14 Javascript
微信小程序抽奖组件的使用步骤
Jan 11 #Javascript
JS数组索引检测中的数据类型问题详解
Jan 11 #Javascript
了不起的11个JavaScript代码重构最佳实践小结
Jan 11 #Javascript
js删除对象中的某一个字段的方法实现
Jan 11 #Javascript
jQuery实现购物车全功能
Jan 11 #jQuery
jQuery实现手风琴特效
Jan 11 #jQuery
iview实现动态表单和自定义验证时间段重叠
Jan 10 #Javascript
You might like
php使用多个进程同时控制文件读写示例
2014/02/28 PHP
php封装的page分页类完整实例
2016/10/18 PHP
Laravel框架实现的上传图片到七牛功能详解
2019/09/06 PHP
解决PHP Opcache 缓存刷新、代码重载出现无法更新代码的问题
2020/08/24 PHP
TNC vs BOOM BO3 第三场2.13
2021/03/10 DOTA
使用javascript访问XML数据的实例
2006/12/27 Javascript
在html页面中包含共享页面的方法
2008/10/24 Javascript
js精度溢出解决方案
2012/12/02 Javascript
DWZ table的原生分页浅谈
2013/03/01 Javascript
js Array操作的最简短最容易理解方法
2013/12/09 Javascript
jquery实现页面图片等比例放大缩小功能
2014/02/12 Javascript
后台获取ZTREE选中节点的方法
2015/02/12 Javascript
jQuery实现可高亮显示的二级CSS菜单效果
2015/09/01 Javascript
详解JS正则replace的使用方法
2016/03/06 Javascript
Bootstrap每天必学之响应式导航、轮播图
2016/04/25 Javascript
jQuery插件passwordStrength密码强度指标详解
2016/06/24 Javascript
微信小程序 教程之wxapp视图容器 scroll-view
2016/10/19 Javascript
详解Node.js模板引擎Jade入门
2018/01/19 Javascript
JavaScript实现简单的隐藏式侧边栏功能示例
2018/08/31 Javascript
浅谈关于iview表单验证的问题
2018/09/29 Javascript
node.js爬取中关村的在线电瓶车信息
2018/11/13 Javascript
VScode格式化ESlint方法(最全最好用方法)
2019/09/10 Javascript
微信内置浏览器图片查看器的代码实例
2019/10/08 Javascript
js实现九宫格抽奖
2020/03/19 Javascript
[02:32]DOTA2亚洲邀请赛 C9战队出场宣传片
2015/02/07 DOTA
[01:01:14]完美世界DOTA2联赛PWL S2 SZ vs Rebirth 第一场 11.21
2020/11/23 DOTA
Python中selenium实现文件上传所有方法整理总结
2017/04/01 Python
django限制匿名用户访问及重定向的方法实例
2018/02/07 Python
python 调用pyautogui 实时获取鼠标的位置、移动鼠标的方法
2019/08/27 Python
python设置环境变量的作用整理
2020/02/17 Python
在tensorflow以及keras安装目录查询操作(windows下)
2020/06/19 Python
H5 canvas中width、height和style的宽高区别详解
2018/11/02 HTML / CSS
在职证明书模板
2015/06/15 职场文书
毕业晚宴祝酒词
2015/08/11 职场文书
世界十大儿童漫画书排名,法国国宝漫画排第五,第二是轰动日本连环
2022/03/18 欧美动漫
win11高清晰音频管理器在哪里?win11找不到高清晰音频管理器解决办法
2022/04/08 数码科技