我们在vue项目中,一般都会使用vuex。在react中,一般都会使用redux。那在小程序中呢?
答案是,还是可以使用vuex。
mupve初始化项目后,有一个页面模板就是使用了vuex。
但是,我一般来说,都是需要全局的store,而不是局部页面的。那如何配置解决呢?
新建一个store后,然后在主入口,main.js中来关联配置。
import Vue from 'vue'
import App from './App'
// api请求接口
import { userLogin, wxloginForBind, userLogout} from '@/api/user'
// 引入store
import store from './store/index'
// 把store挂载到全局
Vue.prototype.$store = store
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue(App)
app.$mount()
/store/index.js内文件长这样:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
sysLogined: false,
token: ''
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
},
actions: {
// 微信登录
loginByWx ({commit}, userData) {
return new Promise((resolve, reject) => {
wxloginForBind(userData).then(res => {
const { data } = res
commit('SET_TOKEN', data.token)
commit('SET_NAME', data.username)
commit('SET_AVATAR', data.iconUrl)
commit('UPDATE_LOGIN', true)
// 保存本地
wx.setStorageSync('sysLogined', true)
wx.setStorageSync('token', data.deviceToken)
wx.setStorageSync('name', data.displayName)
wx.setStorageSync('avatar', data.iconUrl)
resolve()
}).catch(error => {
reject(error)
})
})
},
// 用户主动退出,需要请求后台退出接口
logout ({ commit, state }) {
return new Promise((resolve, reject) => {
userLogout({deviceToken: state.token}).then(() => {
commit('SET_TOKEN', '')
commit('SET_NAME', '')
commit('SET_AVATAR', '')
commit('UPDATE_LOGIN', false)
// 移除本都存储
wx.setStorageSync('sysLogined', false)
wx.removeStorageSync('token')
wx.removeStorageSync('name')
wx.removeStorageSync('avatar')
resolve()
}).catch(err => {
reject(err)
})
resolve()
})
},
// 移除 token
resetToken ({ commit }) {
return new Promise((resolve) => {
commit('SET_TOKEN', '')
commit('SET_NAME', '')
commit('SET_AVATAR', '')
commit('UPDATE_LOGIN', false)
// 移除本都存储
wx.setStorageSync('sysLogined', false)
wx.removeStorageSync('token')
wx.removeStorageSync('name')
wx.removeStorageSync('avatar')
resolve()
})
}
})
export default store
必须注意的是,vuex中保存的数据,需要同步保存到微信的本地存储中。不然,退出去之类的,状态可能就没了。
然后在app.vue中,入口的地方,需要做判断,把本地保存的数据,在小程序加载的时候,重新写入到vuex中去。保持vuex中的数据是对的。
<script>
import { defaultCity } from '@/utils/config.js'
export default {
created () {
// 调用API从本地缓存中获取数据
/*
* 平台 api 差异的处理方式: api 方法统一挂载到 mpvue 名称空间, 平台判断通过 mpvuePlatform 特征字符串
* 微信:mpvue === wx, mpvuePlatform === 'wx'
* 头条:mpvue === tt, mpvuePlatform === 'tt'
* 百度:mpvue === swan, mpvuePlatform === 'swan'
* 支付宝(蚂蚁):mpvue === my, mpvuePlatform === 'my'
*/
},
mounted () {},
onLaunch () {
this.initData()
},
methods: {
initData () {
if (wx.getStorageSync('sysLogined')) {
// 登录状态
let token = wx.getStorageSync('token')
let name = wx.getStorageSync('name') ? wx.getStorageSync('name') : ''
let role = wx.getStorageSync('role') ? wx.getStorageSync('role') : ''
let avatar = wx.getStorageSync('avatar') ? wx.getStorageSync('avatar') : ''
this.$store.commit('UPDATE_LOGIN', true)
this.$store.commit('SET_TOKEN', token)
this.$store.commit('SET_NAME', name)
this.$store.commit('SET_AVATAR', avatar)
}
},
}
}
</script>
<style>
/* 此处定义的是全局公共样式 */
</style>
不能像官方文档说的那样去安装引入,官方文档适应的是原生开发,不是mpvue
那如何使用呢?把官方的github拉取下来,拿到dist目录下的打包好了的文件。全部拷贝到我们项目的static目录下。当做静态资源引入。我把vant-ui的这个包名,该为了weapp目录
然后在需要使用的页面的main.json中,引入一下。
{
"navigationBarTitleText": "记录记录",
"usingComponents": {
"van-button": "/static/weapp/button/index",
"van-search": "/static/weapp/search/index",
"van-tabs": "/static/weapp/tabs/index",
"van-tab": "/static/weapp/tab/index",
"van-dialog": "/static/weapp/dialog/index",
"van-sticky": "/static/weapp/sticky/index"
}
}
然后的对于的.vue文件中,直接使用vant-button
这样的标签。
有时候需要修改vant的样式怎么办?
直接在外面套一层自定义类名,然后相当于加了权重,就会覆盖掉默认的样式了。
类似如下:
.resetpsd-wrap
是我自定义的类目。
<style lang="less">
.resetpsd-wrap {
.van-cell {
padding-top: 48rpx;
padding-bottom: 32rpx;
}
}
</style>
小程序本身是有自己的调用服务器的api请求方法的。但是,使用过了axios后,再也不想回到写回调函数的时候了。
怎么办?
小程序本身是不能继续使用axios了。好消息是,可以使用flyio.js
这个库,本身非常小,语法和axios,简直一模一样。
我使用flyio.js 封装的请求方法:
/**
* 网络请求封装
* fly.js文档参考: https://github.com/wendux/fly
*/
import store from '@/store'
import { serverUrl, apikey, secret, AppId } from './config'
import MD5 from 'js-md5'
const Fly = require('flyio/dist/npm/wx')
const service = new Fly()
service.config.timeout = 60000
service.config.baseURL = serverUrl
service.interceptors.request.use(
config => {
// wx.showLoading({
// title: '加载中',
// mask: true
// })
// 自定义请求头。我这里添加了token,你还可以设置其他的公司需要的请求头。
config.headers['token'] = store.state.token
return config
},
error => {
console.log(error)
Promise.reject(error)
}
)
service.interceptors.response.use(
response => {
// wx.hideLoading()
// 这里,根据后台接口的实际情况来写。这里,返回的都是状态码200的数据。
// 返回结果成功代码为0001,只将请求结果的data字段返回
if (response.data.code === '0001') {
return response.data
}
if (response.data.code === '0004') { // token失效
let token = wx.getStorageSync('token')
if (token) { // 已登录状态下token失效让用户重新登录
// wx.setStorageSync('sysLogined', false)
// wx.removeStorageSync('token')
// wx.removeStorageSync('userId')
store.dispatch('resetToken').then(() => {
wx.showToast({
title: '当前登录失效,请重新登录',
icon: 'none'
})
}).catch(() => {})
}
return response
} else {
wx.hideLoading()
wx.showToast({
title: response.data.message || '请求出错',
icon: 'none',
duration: 3000
})
return Promise.reject(response)
}
},
error => {
wx.hideLoading()
console.log('err' + error)
wx.showToast({
title: '网络错误',
icon: 'none',
duration: 3000
})
return Promise.reject(error)
}
)
export function getRequest (url, param) {
return service.get(url, param || {})
}
/**
*
* @param {*} url 请求接口
* @param {*} param 请求参数
* @param {*} contentType 请求类型,默认application/json, 也可以传入application/x-www-form-urlencoded
*/
export function postRequest (url, param, contentType = 'application/json') {
return service.post(url, param || {}, {headers: {
'content-type': contentType
}})
}
export default service
小程序,本身有一个rpx单位,当然,也可以使用px单位。
rpx单位,小程序是做了适配的。基本上,都会使用这个做布局单位。
但是,但是,mpvue,默认就会把px单位,转换为rpx单位。
有时候,有些字体大小之类的,我不想转,怎么办?
答案是 写成PX
,就不会转了。写什么忽视之类的,不好意思,我没有测试成功过。有可以的,麻烦告诉我一身。
vant-ui, 他的默认但是,其实还是px。布局也还是px单位。
如何把他也改成rpx单位呢?
请参考这篇文章配置一下就可以了:https://blog.csdn.net/qq_36710522/article/details/99409054
设置后不生效,重新打包,把dist目录下的内容删掉,重新开微信开发者工具。
这种项目,表单输入,肯定会有的。怎么搞?
不要在mpvue中使用v-model,双向数据绑定。光标闪的问题。
没有双向绑定?还写不了代码了吗?
<van-field :value="username" input-align="right" clearable placeholder="请输入姓名" @change="onChangeName">
<text slot="label" class="c-grey">客户姓名</text>
</van-field>
:value="username"
使用这种方式来替换v-model
;
绑定@change
事件,然后,在e事件对象中,通过e.mp.dettail拿到改后的值,重新赋值给data中的数据就行了。
onChangeName (e) {
this.username = e.mp.detail
},
注意,如果表单,使用的是小程序的原生input这种。就需要注意了,不要监听@change,虽然模拟器是正常的,真机是有bug的哦。怎么办? 直接搞小程序@input
原生事件。
<input :value="tel" class="input-a" placeholder=" " type="number" maxlength="4" @input="onChangeTel"/>
onChangeTel (e) {
this.tel = e.mp.detail.value
},
小程序背景图片,是不支持本地图片的,只能放到服务器上的url地址。如果一定要搞本地背景图,只有以下几种方法:
A: 把图片转换为base64格式的字符串。百度搜索网站,上传图片上去,拿到base64格式字符串。
然后写样式的时候,就是这样了。
.mine-login-item {
height: 247rpx;
width: 750rpx;
background-image: url(“data:image/png;base64,DAIF…很长的网上转换后的字符串”);
}
B: 换方式,把背景图的位置,换成 标签,当做背景图。然后里面的内容,就只能靠浮动之后,覆盖在上面。改z-index什么的,把内容显示到图片上面。
如果先wx.showToast() 再 wx.hideLoading(),可能导致showToast的时间,很短,如论设置一万年,都不行,因为hideLoading把它关了。
所有,先hideLoading() 后,再调用showToast()
这个问题,哪怕模拟器没有问题,真机上也还是有问题。真的被坑过。
怎么办啊怎么办?
第一步,你可以先安装一个webpack-bundle-analyzer
这个包,查一下各个包的大小。看是不是有很大的。
一般来说,如果你没有做什么不可描述的事情的话,不会很大的。
我就做了不可描述的事情,导致包超大。
具体什么事情呢?正常,密码加密都是MD5,是很小的。但是,我们的后台,密码加密,需要的是
AES
这种加密方式。
这个不好解决么? CryptoJS不就是可以干这个么?
一顿操作猛如虎,接口通了。很满足,很拽,很牛逼。
一打包,我操,什么鬼?那么大?120kb的压缩js包,一下子变成了800+kb。 一下子就不知道咋办了。
最后的办法就是,把AES 加密的方式,从CryptoJS拷出来,不要CryptoJS了。
如果,不上引入了第三方,太大的js包的话,还有一种。
就是static目录放的静态资源图片文件太大了。
我们的UI给我们搞了几个200-300kb的背景图。 总共2M的空间,图片占了一大半?
把图片,压缩。百度搜索在线压缩图片的网站。把图片上传上去,压缩。把几个比较大的,压缩一下。
基本上,每个图片,能够减少70%的大小。
最后,一顿操作后。就只有1.5M的包的大小了。
如果上面的操作,还是不能把包减小到2M的话。
那么,兄弟,很遗憾的告诉你,你可能需要采用分包的形式了。 哈哈哈哈哈哈啊哈哈哈。
我忍不住笑出声了。因为,分包,又是一个需要小心操作的事。
反正,我没有继续弄下去了。有需要的话,就去百度查资料看文档吧。