前言
本文整理了一些uniapp全局变量的实现方式,细节知识来自于uView官网中对uniapp中的全局变量实现,感兴趣的同学可以前往uView官网搜索vuex进行查看
全局变量的实现方式
一般来说在uniapp中有以下几种方式
- 本地存储
- 配置文件
- 挂载到 Vue.prototype
- globalData
- vuex
下面对这5种方式的实现进行介绍
本地存储
永久存储,以app为例即使该应用被关闭,该数据依然会被存储
这是一种永久的存储方式,类似于web的Local Storage(有关于Cookie、Token、SessionStorage、LocalStorage,会整理在另一篇文章中),当我们需要永久存储用户的某一信息时会使用这种方法,但是需要注意使用这种方式需要避免对存储数据的频繁获取和修改操作,因为会对性能产生一定的影响,应用声明周期内的变量,不应该使用此种方式
这种存储方式有 同步和异步两种
同步存储
1
2
3
4
5
|
//同步存储 uni.setStorageSync( "key" , "value" ) //同步获取 let value = uni.getStorageSync( "key" ) console.log("我会等到上边执行完毕后才会执行) |
异步存储
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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
1
2
3
4
|
//如在config.js中 我们导出了一个基础域名 export default { baseUrl: "http://www.test.com" } |
index.js
1
2
3
4
5
6
7
|
//通过import引入这个文件 import config from "../common/config.js" export default { onLoad(){ console.log(config.baseUrl) //baseUrl:"http://www.test.com" } } |
挂载到Vue.prototype
这是一种利用原型的实现方式(有关于js的原型链和继承,会在整理在另一篇文章中),但是这种方式在微信小程序上会有特殊表现
注意:在微信小程序中 模板无法直接读取展示引入的全局变量
main.js
1
2
3
4
|
//这里的config.js参照上文已经写好的文件 import config from "./common/config.js" //将baseUrl挂载到Vue上,此后在页面和组件中就可以通过this.baseUrl的方式去访问 Vue.prototype.baseUrl = config.baseUrl |
页面中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<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
1
2
3
4
5
6
7
8
9
10
11
12
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
<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文件 内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//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中引入
1
2
3
4
5
6
7
|
import store from '@/store' ; // 将store放入Vue对象创建中 const app = new Vue({ store, ...App }) |
在页面中使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<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存储方式一样,对于这点我们可以在下述代码中看到
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
//引入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官网查看相关文档
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
//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文件进行混入
1
2
3
|
//main.js let vuexStore = require( "@/store/$u.mixin.js" ); Vue.mixin(vuexStore); |
将store放到Vue实例中
1
2
3
4
5
6
7
8
|
//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 全局变量内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://juejin.cn/post/6916074986276913166