uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
官网:
js
https://uniapp.dcloud.net.cn/
常用功能示例demo:
类名
js
<view :class="['screen',screenNum!==0?'i_search_g':'' ]"></view>
设置标题
js
uni.setNavigationBarTitle({
title: "剩余次卡"
});
上拉刷新下拉加载
js
// 需要在pages.json加入
// "enablePullDownRefresh": true
export default {
data() {
return {};
},
methods: {},
onLoad: function(options) {
uni.startPullDownRefresh();
},
onPullDownRefresh() {
console.log("结束加载");
setTimeout(function() {
uni.stopPullDownRefresh();
}, 1000);
},
onReachBottom() {
console.log("下拉触底");
}
};
弹框
数据加载
js
uni.showLoading({
title: "加载中"
});
uni.hideLoading();
提示框
js
uni.showToast({});
js
title:显示的提示信息,在没有图标的情况下,文本内容可显示两行
icon: 显示的图标
success:成功图标
loading:加载图标
none:没有图标
image:自定义显示的图标,优先级高于 icon
duration:延迟的时间,弹出框弹出后的显示时间
mask:true/false 是否显示遮罩层
success:接口调用成功的回调函数
fail:接口调用失败的回调函数
complete:不管成功还是失败都会执行的函数
对话框
js
uni.showModal({
title: "暂无数据",
icon: "none"
});
wx.showModal() title:提示信息的标题 content:提示信息的内容 showCancel:true/false 是否显示取消按钮 cancelText:取消按钮的文本内容,不得超过四个字符 cancelColor:取消按钮的文本颜色,默认#000000 confirmText:确认按钮的文本内容,不得超过四个字符 confirmColor:却惹按钮的文本颜色,默认#000000 success:接口成功的回调 fail:接口失败的回调
小程序"↵"换行符号处理
js
var myString = myString.replace(/(\r\n|\n|\r)/gm, "\n");
小程序的换行符为'/n'
只有在 text 里面才能生效,在 view 里面不生效
拨打电话
js
openPhone(phone) {
uni.makePhoneCall({
phoneNumber: 'phone'
})
}
页面传参
A页面获取data-id并跳转:
js
gotoB: function (e) {
var id = e.target.dataset.id //id 为绑定在button组件上的 data-id='123'
wx.navigateTo({
url: './index/index?id='+id,
})
},
B页面获取:
js
onLoad: function (options) {
var id = options.id
console.log(id)
}
$set 更新数据
调用方法: Vue.set( target , key , value) target: 要更改的数据源(可以是一个对象或者数组) key 要更改的具体数据 (索引) value 重新赋的值
js
openUnfold(item,key,index) {
item[key]=!item[key];
this.$set(this.shopData.coupon,index,item);
},
引入全局 sass
在根目录下有一个文件 uni.scss 可以定义全局变量
调用地图
js
<template>
<view @cilck="getLocation">华侨城商业中心</view>
</template>
<script>
//使用微信内置地图查看位置。
export default {
methods: {
getLocation:function(){
uni.getLocation({
type: 'wgs84',
success: function (res) {
uni.openLocation({
latitude: 31.0938140000,//纬度
longitude: 121.5039390000,//经度
name: "MALL华侨城商业中心",
address: '华侨城商业中心'
})
}
})
},
}
<script>
获取用户的当前地址
js
https://lbs.qq.com/miniProgram/jsSdk/jsSdkGuide/jsSdkOverview
getLocationAuth() {
locationCity()
uni.getLocation({
type: 'wgs84',
success: function(res) {
console.log(res, "经纬度");
}
});
},
navigator 点击背景色
设置 navigator 属性 hover-class="none"时,没有点击态效果
设置分享
好友分享
js
左上角的分享
按钮分享,使用 button 添加 open-type="share"
朋友圈分享
左上角的分享
按钮分享无法调用 onShareTimeline
js
<button open-type="share">分享</button>
wx.showShareMenu({
menus: ['shareAppMessagewx', 'shareTimeline'],
withShareTicket:true
});
onShareAppMessage: function () {//分享好友
return {
title: '',
imageUrl:'',
path: '',
}
},
onShareTimeline: function () {//分享朋友圈
return {
title: '',
imageUrl:'',
query: '',
}
},
保存图片
js
uni.chooseImage({
count: 1,
sourceType: ["camera"],
success: function(res) {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePaths[0],
success: function() {
console.log("save success");
}
});
}
});
回到顶部
js
goTop: function (e) { // 一键回到顶部
if (wx.pageScrollTo) {
uni.pageScrollTo({
scrollTop: 0
})
} else {
uni.showModal({
title: '提示',
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
})
}
},
变量全局
globalData 小程序中有个 globalData 概念,可以在 App 上声明全局变量。 Vue 之前是没有这类概念的,但 uni-app 引入了 globalData 概念,并且在包括 H5、App 等平台都实现了。 在 App.vue 可以定义 globalData ,也可以使用 API 读写这个值。 globalData 支持 vue 和 nvue 共享数据。 globalData 是一种比较简单的全局变量使用方式。 定义:App.vue
js
<script>
export default {
globalData: {
text: 'text'
},
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每个页面公共css */
</style>
js 中操作 globalData 的方式如下:
js
赋值:getApp().globalData.text = 'test'
取值:console.log(getApp().globalData.text) // 'test'
hover-class
用于代替 css 的 active
目前支持 hover-class 属性的组件有三个:view、button、navigator。
js
<view
hover-class="hover_act"
class="lg text-gray cuIcon-close"
@click.stop="searchClose"
></view>
.hover_act { transform: rotate(360deg); transition: transform 0.5s; }
检查地址是否授权
js
uni.getSetting({
success: res => {
let authSetting = res.authSetting;
if (authSetting["scope.userLocation"]) {
// 已授权
} else {
uni.showModal({
title: "您未开启地理位置授权",
content: "小程序将无法正常使用",
success: res => {
if (res.confirm) {
nui.openSetting();
}
}
});
}
}
});
编译条件
APP-PLUS App APP-PLUS-NVUE App nvue H5 H5 MP-WEIXIN 微信小程序 MP-ALIPAY 支付宝小程序 MP-BAIDU 百度小程序 MP-TOUTIAO 字节跳动小程序 MP-QQ QQ 小程序 MP-360 360 小程序 MP 微信小程序/支付宝小程序/百度小程序/字节跳动小程序/QQ 小程序/360 小程序 QUICKAPP-WEBVIEW 快应用通用(包含联盟、华为) QUICKAPP-WEBVIEW-UNION 快应用联盟 QUICKAPP-WEBVIEW-HUAWEI 快应用华为
js
#ifdef APP-PLUS
js
https://uniapp.dcloud.io/platform
下载图片
js
wx.downloadFile({
url: "https://www.cardbaobao.com/asset/uploads/image/cbbxcx.png", //需要下载的图片url
success: function(res) {
//成功后的回调函数
wx.saveImageToPhotosAlbum({
//保存到本地
filePath: res.tempFilePath,
success(res) {
wx.showToast({
title: "保存成功",
icon: "success",
duration: 2000
});
},
fail: function(err) {
console.log(err, "授权失败");
if (err.errMsg === "saveImageToPhotosAlbum:fail auth deny") {
wx.showToast({
title: "授权失败,请重新授权",
icon: "none",
duration: 2000
});
}
}
});
}
});
百度 web 版会存在一个问题
由于浏览器于涉及到隐私以及安全方面的考虑, 在使用 geolocation 进行定位的时候, 浏览器会询问用户是否允许共享位置信息; 不管用户同意还是拒绝,操作都会缓存起来
直白来说,就是当用户进入我们的 web 化的 h5 页面时,如果用户点击拒绝授权定位时, 那么以后打开的都会默认拒绝获取定位且无法再次调取定位,也就是说在 h5 页面用户拒绝了定位会一直白屏没数据,
我能想到的解决方式
通过 IP 获取定位 (代码存到百度服务器里面,难以实现)
引导用户清理缓存授权重新定位
当用户拒绝定位时,前端或者后端给一个经纬度的默认值
js
class Request {
constructor(config = {}) {
this.config = {};
this.config.baseUrl = config.baseUrl ? config.baseUrl : "";
this.config.dataType = config.dataType ? config.dataType : "json";
this.config.responseType = config.responseType
? config.responseType
: "text";
this.config.header = config.header ? config.header : {};
this.reqInterceptors = null;
this.resInterceptors = null;
this.interceptors = {
request: fn => {
this.reqInterceptors = fn;
},
response: fn => {
this.resInterceptors = fn;
}
};
}
async get(url, config = {}) {
return this._request("get", url, config);
}
async post(url, config = {}) {
return this._request("post", url, config);
}
async put(url, config = {}) {
return this._request("put", url, config);
}
async delete(url, config = {}) {
return this._request("delete", url, config);
}
setConfig(config = {}) {
this.config = this._deepCopy(this._merge(this.config, config));
}
getConfig() {
return this.config;
}
_request(method, url, config) {
const _this = this;
let newConfig = this._deepCopy(this._merge(this.config, config));
let lastConfig = {};
if (this.reqInterceptors && typeof this.reqInterceptors === "function") {
let reqInterceptors = this.reqInterceptors(newConfig);
if (!reqInterceptors && process.env.NODE_ENV === "development") {
console.warn("请求被拦截,此消息仅在开发环境显示。");
return false;
} else if (
Object.prototype.toString.call(reqInterceptors) === "[object Promise]"
) {
return reqInterceptors;
}
lastConfig = this._deepCopy(reqInterceptors);
} else {
lastConfig = this._deepCopy(newConfig);
}
let fullUrl = this._formatUrl(lastConfig.baseUrl, url);
return new Promise((resolve, reject) => {
uni.request({
url: fullUrl,
method,
data: lastConfig.data ? lastConfig.data : {},
header: lastConfig.header,
dataType: lastConfig.dataType,
responseType: lastConfig.responseType,
async complete(response) {
let res = response;
if (
_this.resInterceptors &&
typeof _this.resInterceptors === "function"
) {
let resInterceptors = _this.resInterceptors(res);
if (!resInterceptors) {
reject("返回值已被您拦截!");
return;
} else if (
Object.prototype.toString.call(resInterceptors) ===
"[object Promise]"
) {
try {
let promiseRes = await resInterceptors;
resolve(promiseRes);
} catch (error) {
reject(error);
}
} else {
res = resInterceptors;
}
}
resolve(res);
}
});
});
}
_formatUrl(baseUrl, url) {
if (!baseUrl) return url;
let formatUrl = "";
const baseUrlEndsWithSlash = baseUrl.endsWith("/");
const urlStartsWithSlash = url.startsWith("/");
if (baseUrlEndsWithSlash && urlStartsWithSlash) {
formatUrl = baseUrl + url.substring(1);
} else if (baseUrlEndsWithSlash || urlStartsWithSlash) {
formatUrl = baseUrl + url;
} else {
formatUrl = baseUrl + "/" + url;
}
return formatUrl;
}
_merge(oldConfig, newConfig) {
let mergeConfig = this._deepCopy(oldConfig);
if (!newConfig || !Object.keys(newConfig).length) return mergeConfig;
for (let key in newConfig) {
if (key !== "header") {
mergeConfig[key] = newConfig[key];
} else {
if (
Object.prototype.toString.call(newConfig[key]) === "[object Object]"
) {
for (let headerKey in newConfig[key]) {
mergeConfig[key][headerKey] = newConfig[key][headerKey];
}
}
}
}
return mergeConfig;
}
_deepCopy(obj) {
let result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === "object") {
result[key] = this._deepCopy(obj[key]);
} else {
result[key] = obj[key];
}
}
}
return result;
}
}
if (!global.$request) {
global.$request = new Request();
}
export default global.$request;
在 main.js 引入
import request from "@/api/request/request.js";
Vue.prototype.$request = request;
request.setConfig({
baseUrl: "https://store.91changqi.com",
dataType: "json",
responseType: "text",
header: {
token: "token from global",
"content-type": "application/x-www-form-urlencoded"
}
});
使用
js
this.$request.get("/api/ptype ").then(res => {
console.log(res);
});