//main.json配置(单个页面的配置)
{
navigationBarTitleText: '',//导航文字
navigationBarBackgroundColor: '',//导航颜色
backgroundTextStyle: "dark",//下拉loading样式
enablePullDownRefresh: true,//启用下拉刷新
onReachBottomDistance: 60//触底距离
}
webpack分包配置(需要修改配置文件),如有错误之处还请指出
mpvue-loader 1.1.2-rc.2 之后的版本已支持分包,请戳我
//webpack.base.conf.js文件
const appEntry = { app: resolve('./src/main.js') }
function getEntry (rootSrc, path) {
var map = {};
glob.sync(rootSrc + '/' + path + '/**/main.js')
.forEach(file => {
var key = relative(rootSrc, file).replace('.js', '');
map[key] = file;
})
return map;
}
let entry;
const pagesEntry = getEntry(resolve('./src'), 'pages')
// 判断app.json文件中是否包含subpackages配置来判断单包、分包
let appJson = require('../src/app.json')
let subpackages = appJson.subpackages || appJson.subPackages || [];
if(subpackages.length){
let entryPath = subpackages.map(({root})=>({root}))
let entryArray = [];
entryPath.forEach( e =>{
entryArray.push(getEntry(resolve('./src'), e['root']))
})
entry = Object.assign({}, appEntry, pagesEntry, ...entryArray)
}else entry = Object.assign({}, appEntry, pagesEntry)
前提是项目代码体积已经超过2M的项目才可以使用此方法
小程序单包最大支持2M,分包后最大可支持8M,故此需要对其进行分包处理
将单个页面的配置单独存储于pages.js内(有点像路由的配置文件)
然后根据功能性来划分相应模块,只有用户触及到某些模块的时候才会去加载
相应的也就提高了进入小程序的加载速度
mpvue-entry1.x.x版本的配置
//pages.js配置(单个页面的配置以及路径)
module.exports = [
{
path: 'pages/index',//主包页面所在路径
config: {
navigationBarTitleText: '',//导航文字
navigationBarBackgroundColor: '',//导航颜色
backgroundTextStyle: "dark",//下拉loading样式
enablePullDownRefresh: true,//启用下拉刷新
onReachBottomDistance: 60//触底距离
}
},
{
path: 'pagesOther/other',//分包页面所在路径
subPackage: true,//是否分包,主包可不用配置此项
config: {
navigationBarTitleText: '',//导航文字
navigationBarBackgroundColor: '',//导航颜色
backgroundTextStyle: "dark",//下拉loading样式
enablePullDownRefresh: true,//启用下拉刷新
onReachBottomDistance: 60//触底距离
}
}
]
mpvue-entry2.0之后的配置,已加入mpvue-config-loader
app.json的路径以及config配置(不需要mpvue-config-loader依赖)
"pages":[
{
"path": "pages/index",
"config": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/order",
"config": {
"navigationBarTitleText": "订单"
}
},
{
"path": "pages/user",
"config": {
"navigationBarTitleText": "我的"
}
},
{
"path": "pagesOther/other",
"subPackage": true,
"config": {
"navigationBarTitleText": "其它"
}
}
]
app.json的路径以及单个vue文件的config配置(需要mpvue-config-loader依赖)
//app.json的路径
"pages":[
"pages/index",
"pages/order",
"pages/user",
{
"path": "pagesOther/other",
"subPackage": true
}
]
//单个vue文件的config配置
export default {
config: {
navigationBarTitleText: '首页'
},
data() {
return {}
},
onLoad() {},
onReady() {},
onShow() {},
methods: {},
computed: {},
watch: {},
components: {}
}
// 版本1
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static/tabBar'),
to: path.resolve(__dirname, '../dist/static/tabBar')
},
{
from: path.resolve(__dirname, '../static'),
to: path.resolve(__dirname, '../dist/static'),
ignore: ['*.png']
}
]),
// 版本2
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static/tabBar'),
to: path.resolve(config.build.assetsRoot, './static/tabBar')
},
{
from: path.resolve(__dirname, '../static'),
to: path.resolve(config.build.assetsRoot, './static'),
ignore: ['*.png']
}
]),
注意:针对三目引入静态资源做require处理,否则不能copy进打包文件或者转为base64
{
"mpvue": "1.0.18",
"mpvue-loader": "1.1.4",
"mpvue-template-compiler": "1.0.18",
}
{
"mpvue": "1.4.7",
"mpvue-loader": "1.4.0",
"mpvue-template-compiler": "1.4.7",
}
多端支持从mpvue2.0开始
在添加v-show指令的元素上,不要使用 display:flex;
安装依赖 npm i gulp gulp-zip gulp-vsftp gulp-ignore dayjs -D
//只针对压缩zip
const fs = require('fs');
const path = require('path');
const gulp = require('gulp');
const vsftp = require('gulp-vsftp');
const gulpIgnore = require('gulp-ignore');//过滤文件插件
const zip = require('gulp-zip');//生成zip插件
const dayjs = require('dayjs');
const distFile = 'dist';//打包目录
const packageInfo = require("./package.json");
let platform = process.argv[process.argv.length - 1] || 'wx';
const gulpZip = () => gulp.src(path.resolve(distFile + '/' + platform + '/**'))
.pipe(gulpIgnore.exclude('*.map'))
.pipe(zip('名称' + platform + '-' + packageInfo.version + '-' + dayjs().format('YYYY-MM-DD HH-mm-ss') + '.zip'))
.pipe(gulp.dest('./'))
//压缩打包文件
gulp.task(platform, gulpZip)
// gulp.task--定义任务
// gulp.src--找到需要执行任务的文件
// gulp.dest--执行任务的文件的去处
// gulp.watch--观察文件是否发生变化
package.json添加指令
"scripts": {
"zip": "npm run build:wx && gulp wx",
"zip:wx": "npm run zip",
"zip:swan": "npm run build:swan && gulp swan",
"zip:tt": "npm run build:tt && gulp tt",
"zip:my": "npm run build:my && gulp my"
}
引入腾讯的微信小程序JavaScript SDK
因为微信小程序wx.getLocation API 返回的是地理位置坐标
所以要用到地址逆解析,然后就是一顿复制
var QQMapWX = require('xxx/qqmap-wx.js')...
然后就出问题了,貌似SDK最后的代码是这样导出的module.exports = QQMapWX;
改为export default QQMapWX; 引入改为import QQMapWX from 'XXX/qqmap-wx-jssdk.js'; 即可
百度的微信小程序JavaScript SDK和其类似,故此不再赘述
注:另一种解决方法,把地图SDK放到static下,别让它被webpack编译就不会报错了
distance(lat1, lng1, lat2, lng2) {
var radLat1 = lat1 * Math.PI / 180.0;
var radLat2 = lat2 * Math.PI / 180.0;
var a = radLat1 - radLat2;
var b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
s = s * 6378.137;
s = Math.round(s * 10000) / 10000;
return s; //返回数值单位:公里
}
取小数点后两位
Math.floor(this.distance(lat1, lng1, lat2, lng2)*100)/100;
安装 and 引入
npm install gcoord --save
<script src="https://unpkg.com/gcoord/dist/gcoord.js"></script>
CommonJS:
const gcoord = require( 'gcoord' );
const { transform, WGS84, GCJ02 } = require( 'gcoord' );
ES Module:
import gcoord from 'gcoord'
import { transform, WGS84, GCJ02 } from 'gcoord';
小例子
var result = gcoord.transform(
[ 116.403988, 39.914266 ], // 经纬度坐标
gcoord.WGS84, // 当前坐标系
gcoord.BD09 // 目标坐标系
)
console.log( result ); // [ 116.41661560068297, 39.92196580126834 ]
npm i autoprefixer -D
在文件.postcssrc.js里面添加"autoprefixer":{}
module.exports = {
"plugins": {
"postcss-mpvue-wxss": {},
"autoprefixer":{}
}
}
1.获取滚动条当前位置
onPageScroll(e){ // 获取滚动条当前位置
console.log(e)
}
2.回到顶部
goTop: function (e) { // 一键回到顶部
if (wx.pageScrollTo) {
wx.pageScrollTo({
scrollTop: 0
})
} else {
wx.showModal({
title: '提示',
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
})
}
}
先看数据请求代码
//数据请求地址
const baseUrl = 'localhost:8080';
const commonHeader = _ => {
//headers每次必传数据存放位置
return {
//...
}
}
//get数据请求
const get = (opt = {}) => {
let time = new Date().getTime();
const str = Object.entries(opt.params).map(e => `${e[0]}=${e[1]}`).join("&").replace(/\s/g, '');
let editHeaders = Object.assign({}, { 'content-type': 'application/json' }, commonHeader())
opt.headers && (editHeaders = Object.assign({}, editHeaders, opt.headers))
return new Promise((resolve, reject) => {
let address = str ? `${opt.url}?${str}&t=${time}` : `${opt.url}?t=${time}`;
wx.request({
url: baseUrl + address,
header: editHeaders,
method: "GET",
success: res => {
setTimeout(_ => {
opt['success'] && opt['success'](res.data);
resolve(res.data)
}, 0)
},
fail: err => {
opt['fail'] && opt['fail'](err);
reject(err)
}
})
})
}
//post数据请求
const post = (opt = {}) => {
let time = new Date().getTime();
let editHeaders = Object.assign({}, { 'content-type': 'application/json' }, commonHeader())
opt.headers && (editHeaders = Object.assign({}, editHeaders, opt.headers))
return new Promise((resolve, reject) => {
wx.request({
url: `${baseUrl}${opt.url}?t=${time}`,
data: opt.data || {},
header: editHeaders,
method: "POST",
success: res => {
setTimeout(_ => {
opt['success'] && opt['success'](res.data);
resolve(res.data)
}, 0)
},
fail: err => {
opt['fail'] && opt['fail'](err);
reject(err)
}
})
})
}
export default { get, post };
// 代码示例
let shopInfo = async _ =>{
let data1 = await this.util.post({
url:'http://XXXXXX',
data:{
demo:'111'
}
})
console.log(data1)
let data2 = await this.util.post({
url:'http://XXXXXX',
data:{
demo:'111'
}
})
console.log(data2)
}
//async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态
//抛出的错误对象会被catch方法回调函数接收到
shopInfo().then(res=>{console.log(res)}).catch(err=>{console.log(err)})
// 小程序内部是不能手动去刷新页面的,这就为状态管理的实现提供了可能性
// 某些状态不需要长期存储,索性投入vuex的怀抱吧。。。
// 引用数据请求
import util from './utils/index';
Vue.prototype.util = util;
// 引用toast提示
import msg from './utils/toast';
Vue.prototype.msg = msg;
// 引用vuex
import store from './store/index';
Vue.prototype.$store = store;
// 发起action =>
this.$store.dispatch('code',{a:1,b:2})
// 获取state数据 =>
this.$store.state.mutations
示例代码
// store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import mutations from './mutations';
import actions from './actions';
Vue.use(Vuex)
export default new Vuex.Store({
modules:{
mutations
},
actions
})
// store/types.js
import keymirror from 'keymirror'
let types = keymirror({
COMMIT_CODE:null,
})
export {types};
// store/actions.js
import {types} from './types.js'
const actions = {
code({commit},val){
commit(types.COMMIT_CODE,val)
},
}
export default actions;
// store/mutations.js
import {types} from './types.js'
// 定义state的值
const state = {
qrcode:null
}
// 每个action的提交引发state的改变
const mutations = {
[types.COMMIT_CODE](state,val){
state.qrcode = val
},
}
// 获取到变化的值
const getters = {
qrcode(state){
return state.qrcode;
}
}
// 导出
export default{
state,
mutations,
getters
}
网络图片的绘制在真机实测的时候是不会显示的,可以调用以下方法先获取本地图片路径,再进行canvas绘制
wx.downloadFile(OBJECT) || wx.getImageInfo(OBJECT)
针对多个图片获取地址的解决方法,将上述两个方法用Promise包装一下
再使用async/await来获取所有的图片本地地址,用catch来抛出图片地址获取异常的情况
//获取线上图片生成本地临时路径
const downImg = val => {
return new Promise((resolve, reject) => {
//判断本地图片路径是否存在
if (val.indexOf('wxfile://') == -1) {
wx.downloadFile({
url: val,
success: res => {
resolve(res.tempFilePath)
},
fail: err => {
reject(err)
}
})
} else {
resolve(val)
}
})
}
优化图片请求方式,采用异步加载
Promise.all([this.downImg(this.QrCodeUrl),
this.downImg(this.Logo)
]).then(res=>{
console.log(res,111)
}).catch(err=>{
console.log(err,222)
})
/**
* ctx,画布对象
* str,需要绘制的文字
* splitLen,切割的长度字符串
* strHeight,每行文字之间的高度
* x,位置
* y,位置
*/
fontLineFeed(ctx, str, splitLen, strHeight, x, y) {
let strArr = [];
for (let i = 0, len = str.length / splitLen; i < len; i++) {
strArr.push(str.substring(i * splitLen, i * splitLen + splitLen));
}
if (str.length > splitLen) {
strArr[0] = strArr[0] + '...';
}
// console.log(strArr[0])
// let s = 0;
// for (let j = 0, len = strArr.length; j < len; j++) {
// s = s + strHeight;
// ctx.fillText(strArr[j], x, y + s);
// }
ctx.fillText(strArr[0], x, y);
}
灵感源自于有赞对虚拟导航的处理方式,判断当前路径是否在路径数组中,存在即回退,不存在则导向新的路径,可解决层级过深的问题
let index = getCurrentPages().findIndex(e => e.route == 'pages/index/main');
if (index > -1) {
wx.navigateBack({
delta: getCurrentPages().length - 1 - index
})
} else {
wx.navigateTo({
url: '/pages/index/main'
})
}
//path路径 示例:'pages/index/main' 如果路径带参数,需要indexOf处理一下
const goPath = path => {
let index = getCurrentPages().findIndex(e => path.indexOf(e.route) > -1);
if (index > -1) {
getCurrentPages()[index].onUnload();
wx.navigateBack({
delta: getCurrentPages().length - (index > 0 ? index + 1 : index),
success: res => {
setTimeout(_ => {
wx.redirectTo({
url: `/${path}`
})
}, 500)
},
fail: err => {}
})
} else {
wx.navigateTo({
url: `/${path}`
})
}
}
跟1px边框实现方式大同小异,使用伪类来实现
element:before {
content: '';
position: absolute;
top: -50%;
bottom: -50%;
left: -50%;
right: -50%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
border: 1px solid #999;
border-radius: 6rpx;
}
const isAuth = (name) => {
return new Promise((resolve, reject) => {
wx.getSetting({
success: (res) => {
if (res.authSetting[name]) {
resolve();
} else {
reject();
}
},
fail: (err) => {
reject(err);
}
})
})
}
只看getLocation API fail的处理方式
fail: err => {
wx.hideLoading();
//无定位判断
if(wx.getStorageSync('QQmap')&&!wx.getStorageSync('QQmap').mapGet){
reject('位置信息获取失败,启用无定位搜索');
}else{
wx.getSetting({
success: ok => {
if(!(ok.authSetting['scope.userLocation'])){
//小程序位置信息权限关闭
console.log('小程序定位未开启')
model(1);
}else{
console.log('手机定位未开启')
model(2);
}
},
fail: error => {
console.log('权限获取失败')
}
})
reject('位置信息获取失败');
}
}
地理位置授权
const model = val => {
wx.showModal({
title: '定位失败',
content: `未获取到你的地理位置,请检查${val==1?'小程序':'微信APP'}是否已关闭定位权限,或尝试重新打开小程序`,
// showCancel:false,
success: res => {
if (res.confirm) {
console.log('用户点击确定')
if(val==1){
wx.redirectTo({
url: '/pages/wx-auth/main?type=1'
})
}
//调用wxLogin接口
} else if (res.cancel) {
console.log('用户点击取消')
// model(val);
//调用wxLogin接口
}
}
})
}
注:小程序基础库 2.1.2 开始支持 wx.getLaunchOptionsSync() 方法
可使用navigator标签,但想要在另外一个小程序来接受参数的话就需要使用到extra-data属性
但在跳转过去的onShow(options){}里,并未获取到referrerInfo信息
解决方法:使用小游戏的 wx.getLaunchOptionsSync() 方法
<textarea :show-confirm-bar="false"></textarea>
1.scroll-view 中的需要滑动的元素不可以用 float 浮动;
2.scroll-view 中的包裹需要滑动的元素的大盒子用 display:flex; 是没有作用的;
3.scroll-view 中的需要滑动的元素要用 dislay:inline-block; 进行元素的横向编排;
4.包裹 scroll-view 的大盒子有明确的宽和加上样式--> overflow:hidden;white-space:nowrap;
滚动吸顶利用onPageScroll和createIntersectionObserver均有操作延迟,暂时用position: sticky解决
方法1:使用button组件来使用此功能,示例代码如下:
<button open-type="openSetting" bindopensetting="callback">打开设置页</button>
方法2:由点击行为触发wx.openSetting接口的调用,示例代码如下:
<button bindtap="openSetting">打开设置页</button> => openSetting(){wx.openSetting()}
其他方法:在点击中调用showModal,showModal的回调再调用openSetting也可以
this.$forceUpdate();
Object.assign(this.$data, this.$options.data())
canvas的绘制函数为异步函数,故作延时处理之后导出裁剪区域图片,再做图片上传
胡成全mpvue-platform-sample项目示例,请戳我
// ./src/app.vue
import Raven from 'sentry-weapp'
export default {
onLaunch() {
Raven.config('https://xxx@your.example.com/x', {
release: '1.0.0', //版本号
environment: 'production',
allowDuplicates: true, // 允许相同错误重复上报
sampleRate: 0.5 // 采样率
}).install()
},
onError(msg) {
// Raven.captureException(msg)
Raven.captureException(msg, {
level: 'error'
})
}
}
// ./build/webpack.prod.conf.js
new UglifyJsPlugin({
sourceMap: true
})
// ./config/index.js文件
build: {
// ...
productionSourceMap: true, // 生产环境开启map文件生成
// ...
}
webpack中开启了map映射,但是打包一直没有map文件。
经检查webpack的配置都没有问题,那为什么没有生成对应的map文件呢?
最终找到的原因是使用uglifyjs-webpack-plugin这个插件导致的。
在webpack的devtool文档中,有一块不起眼的小字:
When using the uglifyjs-webpack-plugin you must provide the sourceMap: true option to enable SourceMap support.
也就是当使用了uglifyjs-webpack-plugin 插件时,sourceMap这个值的默认值是false,不开启map。
如果要启用map,需要在插件中配置sourceMap值为true。
隐藏导航栏,获取手机状态栏高度wx.getSystemInfoSync()['statusBarHeight']),自定义顶部状态栏即可达到适配
针对自定义状态栏以组件的形式要考虑以下内容
返回按钮 | 导航栏背景,中间标题文字、颜色 | 是否固定顶部 |
---|---|---|
是否展示,展示箭头颜色 | 父组件传入 | 布尔值 |
以vue为例,需要安装weixin-js-sdk依赖
//src/main.js
const wx = require('weixin-js-sdk');
//挂载原型
Vue.prototype.wx = wx;
//页面跳转小程序
this.wx.miniProgram.reLaunch({
url: "/pages/index/index"
})
点击收起/打开赞赏名单
赞赏名单 🎨
昵称 | 赞赏时间 | 赞赏方式 | 赞赏金额 |
---|---|---|---|
**丽 | 2019-12-26 | 微信 | ¥28.00 |
个人微信号:zyh941109,感谢以上朋友,十分感谢!!!