详解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 动态加载脚本的4种方法
May 05 Javascript
学习ExtJS accordion布局
Oct 08 Javascript
EXTJS FORM HIDDEN TEXTFIELD 赋值 使用value不好用的问题
Apr 16 Javascript
jQuery实现可拖动的浮动层完整代码
May 27 Javascript
javascript常用代码段搜集
Dec 04 Javascript
JavaScript中通过prototype属性共享属性和方法的技巧实例
Mar 13 Javascript
js实现有过渡渐变效果的图片轮播相册(兼容IE,ff)
Jan 19 Javascript
浅析JavaScript Array和string的转换(推荐)
May 20 Javascript
JS基于onclick事件实现单个按钮的编辑与保存功能示例
Feb 13 Javascript
详解windows下vue-cli及webpack 构建网站(三)使用组件
Jun 17 Javascript
jQuery实现的页面遮罩层功能示例【测试可用】
Oct 14 jQuery
layui prompt 设置允许空白提交的方法
Sep 24 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
Banner程序
2006/10/09 PHP
PHP 替换模板变量实现步骤
2009/08/24 PHP
基于PHP服务端图片生成缩略图的方法详解
2013/06/20 PHP
php中函数前加&amp;符号的作用分解
2014/07/08 PHP
Laravel实现通过blade模板引擎渲染视图
2019/10/25 PHP
关于删除时的提示处理(确定删除吗)
2013/11/03 Javascript
javascript实现json页面分页实例代码
2014/02/20 Javascript
最简单的JavaScript验证整数、小数、实数、有效位小数正则表达式
2015/04/17 Javascript
Jquery使用css方法改变样式实例
2015/05/18 Javascript
js实现的下拉框二级联动效果
2016/04/30 Javascript
使用smartupload组件实现jsp+jdbc上传下载文件实例解析
2017/01/05 Javascript
详谈js遍历集合(Array,Map,Set)
2017/04/06 Javascript
HTML5+JS+JQuery+ECharts实现异步加载问题
2017/12/16 jQuery
vue使用swiper实现中间大两边小的轮播图效果
2019/11/24 Javascript
JS如何实现封装列表右滑动删除收藏按钮
2020/07/23 Javascript
Node.JS如何实现JWT原理
2020/09/18 Javascript
python标准算法实现数组全排列的方法
2015/03/17 Python
python在windows和linux下获得本机本地ip地址方法小结
2015/03/20 Python
python通过伪装头部数据抵抗反爬虫的实例
2018/05/07 Python
python远程连接MySQL数据库
2019/04/19 Python
python二进制文件的转译详解
2019/07/03 Python
pandas读取CSV文件时查看修改各列的数据类型格式
2019/07/07 Python
Python使用requests xpath 并开启多线程爬取西刺代理ip实例
2020/03/06 Python
python压包的概念及实例详解
2021/02/17 Python
XML文档面试题
2015/08/05 面试题
企业军训感想
2014/02/07 职场文书
大学生职业规划书的范本
2014/02/18 职场文书
仓库管理员岗位职责
2014/03/19 职场文书
小学生感恩老师演讲稿
2014/08/28 职场文书
投标承诺函范文
2015/01/21 职场文书
辩护词格式
2015/05/22 职场文书
优秀党员主要事迹范文
2015/11/05 职场文书
2016银行求职自荐信
2016/01/28 职场文书
初中英语教学反思范文
2016/02/15 职场文书
个人自我鉴定怎么写?
2019/07/01 职场文书
深入理解java.lang.String类的不可变性
2021/06/27 Java/Android