【uniapp】五、通用插件封装与运行平台判断(续集)

2023-11-16

一、uniapp项目目录

uniapp给我们的项目框架介绍,有一些文件夹是没有在模板中内置的,因此我们需要自己手动创建以下,例如最外层的components,用来放置我们的一些全局通用组件

┌─components            符合vue组件规范的uni-app组件目录
│  └─comp-a.vue         可复用的a组件
├─pages                 业务页面文件存放的目录
│  ├─index
│  │  └─index.vue       index页面
│  └─list
│     └─list.vue        list页面
├─static                存放应用引用的本地静态资源(如图片、视频等)的目录,注意: 静态资源只能存放于此
├─uni_modules           存放uni_module规范的插件。
├─wxcomponents          存放小程序组件的目录,详见
├─main.js               Vue初始化入口文件
├─App.vue               应用配置,用来配置App全局样式以及监听 应用生命周期
├─manifest.json         配置应用名称、appid、logo、版本等打包信息,详见
└─pages.json            配置页面路由、导航条、选项卡等页面类信息,详见

如下图,在开发的过程中,我依据vue项目的开发习惯,在pages中依照业务功能来创建功能分类文件夹,最常见的是按照首页的tabbar来区分功能模块,每一个文件夹中存放该功能涉及的所有页面,且每一个功能文件夹中还有一个单独的components文件夹用于放置该仅功能文件夹中的页面依赖的组件。

二、通用插件封装

uniapp选择使用vue.js作为开发框架,我们可以提供过插件封装提高uniapp使用的体验。vue 插件官方介绍链接
通过引入插件,我们可以极大的提升我们的开发效率。
在封装前我们需要写一个 config 文件,方便我们快速自定义一些颜色和请求路径等。

//congif.js
const config = {
	baseUrl:'https://example.cn',//请求的基本路径
	modalColor:'#5271FF', //弹窗颜色 
}

module.exports = config

1 弹窗插件

在小程序中,如果我们没有自定义弹窗和拟态框组件的话一般都是使用官方的showModal或者showToast api来进行一些用户交互。这种非常频繁使用到的操作非常适合封装起来快速调用。具体代码如下

插件代码

const config = require('../config.js')

var message = {
	toast(title, type = 'text') {
		if (title.length > 15) {
			console.error('toast长度超过15个字符,当前长度为' + title.length)
			return
		}
		var icon = 'none'
		if (type) {
			switch (type) {
				case 'text':
					icon = 'none'
					break
				case 'suc':
					icon = 'success'
					break
				case 'err':
					icon = 'error'
					break
			}
		}
		uni.showToast({
			title,
			icon
		})
	},
	confirm(title, confirmColor) {
		return new Promise((res, rej) => {
			uni.showModal({
				title,
				cancelColor: '#b6b6b6',
				confirmColor: confirmColor || config.modalColor,
				success: (result) => {
					if (result.cancel) {
						rej(result)
					} else if (result.confirm) {
						res(result)
					}
				}

			})
		})
	},
	async message(content, confrimText) {
		return new Promise((res) => {
			uni.showModal({
				title: '提示',
				content,
				showCancel: false,
				confirmColor: config.modalColor,
				success: (result) => {
					res(result)
				}
			})
		})
	}
}
module.exports = message

示例调用

this.message.toast('回答已删除')

2 请求插件

在uni-app中直接使用官方提供的 uni.request(OBJECT) 这个api来进行请求的调用,进行二次封装,以减少调用时的代码量以及进行一些全局配置。具体代码如下

插件代码

//http.js
const config = require('../config.js')
const message = require('./message.js')
var http = {
	post(path, params, contentType = 'form', otherUrl, ) {
		return new Promise((resolve, reject) => {
			var url = (otherUrl || config.baseUrl) + path
			if (!checkUrl(url)) {
				rej('请求失败')
			}
			uni.request({
				method: 'POST',
				url,
				header: {
					"Content-Type": contentType === 'json' ? "application/json" :
						"application/x-www-form-urlencoded"
				},
				data: params,
				success: (res) => {
					console.log('request:POST请求' + config.baseUrl + path + ' 成功', res.data)
					resolve(res.data)
				},
				fail: (err) => {
					message.toast('请求失败', 'err')
					console.error('request:请求' + config.baseUrl + path + ' 失败', err)
					reject('请求失败')
				}
			})
		})
	},
	put(path, params, contentType = 'form', otherUrl, ) {
		return new Promise((resolve, reject) => {
			var url = (otherUrl || config.baseUrl) + path
			if (!checkUrl(url)) {
				rej('请求失败')
			}
			uni.request({
				method: 'PUT',
				url,
				header: {
					"Content-Type": contentType === 'json' ? "application/json" :
						"application/x-www-form-urlencoded"
				},
				data: params,
				success: (res) => {
					console.log('request:PUT请求' + config.baseUrl + path + ' 成功', res.data)
					resolve(res.data)
				},
				fail: (err) => {
					message.toast('请求失败', 'err')
					console.error('request:PUT请求' + config.baseUrl + path + ' 失败', err)
					reject('请求失败')
				}
			})
		})
	},

	get(path, params, otherUrl) {
		return new Promise((resolve, reject) => {
			var url = (otherUrl || config.baseUrl) + path
			if (!checkUrl(url)) {
				return
			}
			uni.request({
				url,
				data: params,
				success: (res) => {
					console.log('request:GET请求' + config.baseUrl + path + ' 成功', res.data)
					resolve(res.data)
				},
				fail: (err) => {
					message.toast('请求失败', 'err')
					console.error('request:GET请求' + config.baseUrl + path + ' 失败', err)
					reject(err)
				}
			})

		})

	},
	delete(path, params, otherUrl) {
		return new Promise((resolve, reject) => {
			var url = (otherUrl || config.baseUrl) + path
			if (!checkUrl(url)) {
				return
			}
			uni.request({
				url,
				data: params,
				method: "DELETE",
				success: (res) => {
					console.log('request:DELETE请求' + config.baseUrl + path + ' 成功', res.data)
					resolve(res.data)
				},
				fail: (err) => {
					message.toast('请求失败', 'err')
					console.error('request:DELETE请求' + config.baseUrl + path + ' 失败', err)
					reject(err)
				}
			})

		})

	},

	async upload(path, fileArray, otherUrl) {

		if (typeof fileArray !== 'object') {
			console.error('request:参数错误,请传入文件数组')
			return
		}
		var url = (otherUrl || config.baseUrl) + path
		if (!checkUrl(url)) {
			return
		}
		var arr = []
		for (let i in fileArray) {
			const res = await uni.uploadFile({
				url: otherUrl || config.baseUrl + path,
				filePath: fileArray[i],
				name: 'file'
			})
			console.log(res)
			if (res[0]) {
				console.error('request:上传失败', res[0])
				return
			}
			arr.push(JSON.parse(res[1].data).data)
		}
		return arr
	},

}

function checkUrl(url) {
	var urlReg = /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/;
	if (!urlReg.test(url)) {
		console.error('request:请求路径错误' + url)
		return false
	}
	return true
}
module.exports = http

示例调用

async getAnswer() {
  const res = await this.http.get('/applet/answerList', {
    qId: this.question.id,
  })
  if (res.code === 200) {
    return res.data
  } else {
    this.message.toast('请求失败')
    return false
  }
}

在上面的代码中我们可以看到,我们引入两个依赖文件分别是config和message 这个在下面会说的,在http对象中有五个方法,分别是post,get,update,delete对应着 restful api 的增删查改操作,还有一个upload 方法用来上传文件。在小程序中请求我们不需要考虑跨域的问题,我们的默认请求路径是从 config这个依赖文件中获取的。而这时候我们还可以利用第一个 弹窗插件 快速的进行消息提示。

3 存储插件

在uniapp中我们有两种全局数据的存储方式 一种是globalData,通过在App.vue中添加globalData这个值来进行数据全局化,例如我们可以用来保存我们的小程序版本。

export default {
  globalData: {
    version: '1.0.0'
  }
}

但是globalData的数据不是持久化的,当我们退出小程序再进入的时候就重新初始化了,所以我们还有一种全局数据存储方式是storage,类比我们web端的localstroge,使用方式也几乎一样。通过官方提供的api实现本地存储的效果:uni.setStorage(OBJECT)uni.setStorageSync(KEY,DATA)uni.getStorage(OBJECT)uni.getStorageSync(KEY)uni.getStorageInfo(OBJECT)uni.getStorageInfoSync()uni.removeStorage(OBJECT)uni.removeStorageSync(KEY)uni.clearStorage()uni.clearStorageSync()
在小程序中往往没有web端那么复杂的数据结构,不过,uniapp小程序也可以使用vuex或者pinia作为一个全局数据管理的库,不过本地存储实现简单,简单存储是可以使用的。如果想要省略setData操作可以用 proxy 劫持存储的值去存在本地。

插件代码

var store = {
	_init(){
		if(uni.getStorageSync('store')==''){
			uni.setStorageSync('store',{})
			return
		}
		const data = uni.getStorageSync('store')
		for(let i in data){
			if(!this[i]){
				this[i] = data[i]
			}
		}
	},
	setData(key,value){
		if(key == '_init'||key=='setData'){
			console.error('store:非法key值',key)
			return
		}
		this[key] = value
		uni.setStorageSync('store',this)
		console.log(uni.getStorageSync('store'))
	}
}

module.exports = store

示例使用

this.store.setData('user',{name:'oil'}) // 赋值
console.log(this.store.user) // 读值

4 表单验证插件

表单验证是使用的是一个很轻量开源的表单验证库JSValidate。 JSValidate gitee链接

示例调用

// validate.js
const validate = {
	userForm:{
		intro:	'@个人简介|require',
		college: '@学校|require!请选择你的学校',
		nickname:'@昵称|require'
	}
}

module.exports = validate

在表单中写入一个表单验证方法,如果条件不符合的话就使用弹窗进行提示

//form.js
validateForm() {
  // 表单验证方法
  const validate = require("./validate")
  const validator = new this.validator()
  var result = validator.check(validate.userForm, this.form, false)
  if (result !== true) {
    this.message.message(result)
    return false
  }
  return true
}

5 时间处理插件

关于时间处理插件我在项目中使用的也是一个开源的轻量级js库 day.js,具体的使用方式参考官方文档,day.js几乎包含了所有时间处理相关的操作,例如时间对比,时间转换等。 day.js官方文档链接
day.js其中有一项功能特别常用,就是一个相对时间转换的功能,相对时间转换就是将一个时间字符串例如年月日时分秒转换成几秒前,十分钟前,几个月前等等。使用的方式如下代码,我们使用vue的computed来进行时间字符串的处理,通过 闭包computed方法内传入时间字符串参数,然后通过day.js的formNow方法返回一个中文的相对时间。date就是我封装后引入的插件了。

示例代码

computed: {
  relativeDate() {
    return (date) => {
      return this.date(date).fromNow()
    }
  }
}

6 插件统一出口

当我们拥有了很多个插件之后(如下图),我们的插件之间可能会共享一些配置,例如上文中的config.js,接下来我们可以写一个入口文件index.js用来将我们写的插件引入,然后在main.js中安装我们的插件。

示例代码

// index.js
const http = require('./lib/http')
const message = require('./lib/message')
const router = require('./lib/router')
const validator = require('./lib/validator')
const date = require('./lib/date')
const store = require('./lib/store')
const to = require('./lib/to')
const myplugins = {
  message,
  http,
  router,
  validator,
  date,
  store,
  to,
  install(Vue) {
    this.store._init()
    for (let i in this) {
      if (i == 'install') {
        continue
      }
      Vue.prototype[i] = this[i]
    }

    delete this.install
  }
}

export default myplugins

// main.js
import Vue from 'vue'
import myplugins from './oil-uni/index.js'
Vue.use(myplugins)
app.$mount()

我们在入门文件中定义了一个对象叫做mypluginsmyplugins上除了我们写好的方法还有一个特殊的方法就是installinstall的作用就是在我们使用Vue.use()的时候会将Vue的构造器传入install方法作为第一个参数,然后我们将所有方法都绑定在Vue的原型链上。
安装后,我们只需要在页面或组件的js中使用 this. + xx插件 就可以访问到封装的插件了。

二 运行平台判断

判断使用平台,方便根据不同平台做出差异性适配

使用

// @/utils/Config.tsimport {EPlatform} from './EPlatform';
import {isH5, Platform} from '@/utils/Platform'
 
/**配置信息*/
export default class Config {
  /**http请求根目录*/
  static get httpBaseUrl(): string {
    if (isH5) {
      return '/'
    } else {
      return 'http://demo.cn/'
    }
  }
}

条件编译

/**枚举EPlatform*/
export enum EPlatform {
  /**App*/
  AppPlus = 'APP-PLUS',
  /**App nvue*/
  AppPlusNvue = 'APP-PLUS-NVUE',
  /**H5*/
  H5 = 'H5',
  /**微信小程序*/
  MpWeixin = 'MP-WEIXIN',
  /**支付宝小程序*/
  MpAlipay = 'MP-ALIPAY',
  /**百度小程序*/
  MpBaidu = 'MP-BAIDU',
  /**字节跳动小程序*/
  MpToutiao = 'MP-TOUTIAO',
  /**QQ小程序*/
  MpQq = 'MP-QQ',
  /**360小程序*/
  Mp360 = 'MP-360',
  /**微信小程序/支付宝小程序/百度小程序/字节跳动小程序/QQ小程序/360小程序*/
  Mp = 'MP',
  /**快应用通用(包含联盟、华为)*/
  QuickappWebview = 'quickapp-webview',
  /**快应用联盟*/
  QuickappWebviewUnion = 'quickapp-webview-union',
  /**快应用华为*/
  QuickappWebviewHuawei = 'quickapp-webview-huawei',
}
 
/**使用条件编译获取平台信息*/
export function ifDefPlatform(): EPlatform {
  let platform: EPlatform
  //#ifdef APP-PLUS
  platform = EPlatform.AppPlus;
  //#endif
  //#ifdef APP-PLUS-NVUE
  platform = EPlatform.AppPlusNvue;
  //#endif
  //#ifdef H5
  platform = EPlatform.H5;
  //#endif
  //#ifdef MP-WEIXIN
  platform = EPlatform.MpWeixin;
  //#endif
  //#ifdef MP-ALIPAY
  platform = EPlatform.MpAlipay;
  //#endif
  //#ifdef MP-BAIDU
  platform = EPlatform.MpBaidu;
  //#endif
  //#ifdef MP-TOUTIAO
  platform = EPlatform.MpToutiao;
  //#endif
  //#ifdef MP-QQ
  platform = EPlatform.MpQq;
  //#endif
  //#ifdef MP-360
  platform = EPlatform.Mp360;
  //#endif
  //#ifdef MP
  platform = EPlatform.Mp;
  //#endif
  //#ifdef quickapp-webview
  platform = EPlatform.QuickappWebview;
  //#endif
  //#ifdef quickapp-webview-union
  platform = EPlatform.QuickappWebviewUnion;
  //#endif
  //#ifdef quickapp-webview-huawei
  platform = EPlatform.QuickappWebviewHuawei;
  //#endif
  return platform
}
 
/**平台类型*/
export const Platform: EPlatform = ifDefPlatform()
/**默认导出平台类型*/
export default Platform
 
/**App*/
export const isAppPlus = Platform == EPlatform.AppPlus
/**App nvue*/
export const isAppPlusNvue = Platform == EPlatform.AppPlusNvue
/**H5*/
export const isH5 = Platform == EPlatform.H5
/**微信小程序*/
export const isMpWeixin = Platform == EPlatform.MpWeixin
/**支付宝小程序*/
export const isMpAlipay = Platform == EPlatform.MpAlipay
/**百度小程序*/
export const isMpBaidu = Platform == EPlatform.MpBaidu
/**字节跳动小程序*/
export const isMpToutiao = Platform == EPlatform.MpToutiao
/**QQ小程序*/
export const isMpQq = Platform == EPlatform.MpQq
/**360小程序*/
export const isMp360 = Platform == EPlatform.Mp360
/**微信小程序/支付宝小程序/百度小程序/字节跳动小程序/QQ小程序/360小程序*/
export const isMp = Platform == EPlatform.Mp
/**快应用通用(包含联盟、华为)*/
export const isQuickappWebview = Platform == EPlatform.QuickappWebview
/**快应用联盟*/
export const isQuickappWebviewUnion = Platform == EPlatform.QuickappWebviewUnion
/**快应用华为*/
export const isQuickappWebviewHuawei = Platform == EPlatform.QuickappWebviewHuawei
/**是否开发环境*/
export const isDevelopment = process.env.NODE_ENV == 'development'
/**是否线上环境*/
export const isProduction = process.env.NODE_ENV == 'production'
/**抖音小程序*/
export const isMpDouyinApp = uni.getSystemInfoSync().appName == 'Douyin'
/**头条小程序*/
export const isMpToutiaoApp = uni.getSystemInfoSync().appName == 'Toutiao'
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【uniapp】五、通用插件封装与运行平台判断(续集) 的相关文章

随机推荐

  • STL容器的线程安全

    众所周知 STL容器不是线程安全的 对于vector 即使写方 生产者 是单线程写入 但是并发读的时候 由于潜在的内存重新申请和对象复制问题 会导致读方 消费者 的迭代器失效 实际表现也就是招致了core dump 另外一种情况 如果是多个
  • firefox os_如何在电视上测试Firefox OS应用

    firefox os One of my responsibilities in my new role in Partner Engineering at Mozilla is testing HTML5 powered apps and
  • 解决git中出现的“bash syntax error near unexpected token ’(‘”错误

    今天来分享一篇关于我在git使用过程中出现的一个错误 错误信息 bash syntax error near unexpected token 翻译过来就是提示我在 这里有错误 而这个错误是我在使用git commit提交时候产生的 我当时
  • 4. Docker 构建镜像

    Docker 构建镜像 docker制作镜像通常是通过两种方式来实现的 第一种是通过容器的 commit 第二种是通过 Buildfile来实现的 docker commit 打包镜像 容器在运行过程中我们难免会做一些修改 比如运行的mys
  • 程序框架---缩进(Python)

    缩进 类定义 函数定义 选择结构 循环结构 with块 行尾的冒号表示缩进的开始 python程序是依靠代码块的缩进来体现代码之间的逻辑关系的 缩进结束就表示一个代码块结束了 同一级别代码块的缩进量必须相同 一般而言 以4个空格或一个TAB
  • OLED透明屏:在广告领域中的应用,为品牌注入更强的视觉冲击

    OLED透明屏作为一项引人注目的技术创新 其独特的透明度和高清晰度为各行各业带来了全新的展示和创意空间 本文将详细介绍其透明度 高对比度 超薄柔性设计以及强大的颜色表现力 并探讨其在零售 汽车和建筑等领域的应用前景 一 透明度 开启全新的透
  • 聊透spring @Configuration配置类

    本章节我们来探索Spring中一个常用的注解 Configuration 我们先来了解一下该注解的作用是 用来定义当前类为配置类 那啥是配置类啊 有啥用啊 这个我们得结合实际使用场景来说 通常情况下 加了 Configuration的配置类
  • 机器学习——决策树(Decision Trees)

    决策树 决策树是机器学习中一种最为常见的算法 顾名思义 决策树是基于树结构来进行决策的 这恰是人类在面对决策问题时一种很自然的处理机制 决策树的生成算法可以说是信息论的一种应用 但它其实只用到了信息论中的一小部分思想 因此对信息论有个基础性
  • Python系列教程-目录

    转载至 http www cricode com 3086 html Python初级教程 Python快速教程 手册 Python基础01 Hello World Python基础02 基本数据类型 Python基础03 序列 Pytho
  • CSS 之层叠规则(权级、权重、顺序)详解

    文章目录 参考 描述 定义 层叠 层叠与冲突 规则 权重 优先级 权重值的叠加 顺序 权级 权级 层叠规则的运用 顺序 尾声 参考 项目 描述 MDN WEB Docs 优先级 Amily mo 令人烦恼的css选择器权值问题 Amily
  • 《TCP/IP网络编程》--基于TCP实现字符串对话和文件传输

    1 基于TCP实现字符串对话 主要需求 服务器端和客户端各传递 1 次字符串 基于 TCP 协议 传递字符串前先以 4 字节整数型方式传递字符串长度 剩余部分为字符串数据 注 下面的代码基于 Windows 系统实现 1 1 服务器端 gc
  • Java中实现ftp下载文件至本地(详细)

    Java中实现ftp下载文件至本地 详细 欢迎关注蚕豆公众号 不定时分享技术 同时欢迎加入蚕豆技术群哦 扫描公众号点击关于作者加群 2020 09 13 今天记录一下java中实现ftp下载文件至本地的功能模块 同此与大家交流分享有什么不对
  • js每日定时请求接口

    需求是每日十点请求一次接口 初始方法是写一个一分钟的轮询 定时查询系统时间 如果时间为10点就执行请求函数 但是考虑这样太浪费资源 在师傅的帮助下找到了一个更优的方法 计算当前时间和目标时间的时间间隔 如果超过 则设置定时查询的时间间隔为距
  • 线段树合并例题

    https www luogu com cn problem P3224 1 永无乡 题意 给 n 个岛屿 每个岛有一个标号 初始修有 m 条路 有两个操作 操作1 为 给两个岛屿之间修路 操作2为求出 所有能从当前岛屿到达的岛 中标号第k
  • shell脚本之if多分支和case分支语句

    文章目录 一 多分支if语句 二 case分支语句 三 实操 3 1 系统控制服务脚本 控制服务的启动 重启 停止 3 2 根据学生的成绩 判断优秀 良好 和不及格几个等级 3 3 删除家目录 3 4 剪刀石头布 电脑与人 3 5 case
  • 软件测试从业人员学历和专业分布情况

    随着 十四五 规划对科技创新提出了更迫切的要求 国内人工智能 AI 物联网 大数据 云计算等IT产业得到了迅速发展 可是现阶段 我国软件测试基础人才不足 已成为制约我国软件产业发展的瓶颈 据国家权威部门统计 中国软件测试人才缺口近40万 并
  • 华为手机连电脑_华为手机也能连苹果电脑!文件互传超方便~

    每个人手机里 都存了许多回忆 有人会珍藏很多难忘的影像 有人会保存甜蜜或珍贵的聊天记录 也有人小心翼翼地保管着自己的通讯录 俗话说 未雨绸缪才能有备无患 为防止手机里的数据丢失 做好备份实在是太有必要了 今天花部长就来给大家讲一讲 华为 荣
  • jsp自定义tag标签

    首先定义use tag 存放目录在 WEB INF tags use tag div p This is a test p br div
  • JAVA中方法的值传递

    首先了解在程序设计语言中 有关将参数传递给方法的一些专业术语 按值调用 call by value 表示方法接收的是调用者提供的值 而按引用调用 call by reference 表示方法接收的是调用者提供的变量地址 一个方法可以修改传递
  • 【uniapp】五、通用插件封装与运行平台判断(续集)

    一 uniapp项目目录 uniapp给我们的项目框架介绍 有一些文件夹是没有在模板中内置的 因此我们需要自己手动创建以下 例如最外层的components 用来放置我们的一些全局通用组件 components 符合vue组件规范的uni