
让小程序开发进入 `tailwind jit` 时代!
让小程序开发进入 tailwind jit
时代!
把
tailwindcss JIT
思想带入小程序开发吧!
笔者几个月前写了一个 tailwindcss-miniprogram-preset 预设,可是这个预设方案,可操作性非常的小,也不能兼容 tailwindcss v2/v3
的 Just in time
引擎,同时在写法上也有一定的变体。
于是笔者又设计了一个方案,并最终实现了 weapp-tailwindcss-webpack-plugin
。相比原先 preset
or postcss
方案,这个方案有很多的优势:
- 为
jit
设计,兼容v2/v3
2个版本的jit
引擎 - 开发者不需要额外记忆任何的写法变体,带来原汁原味的
tailwindcss
开发体验 - 兼容基于
webpack v4/v5
的小程序多端开发框架,简单易用
那么接下来就来展示一个基于 uni-app
的 demo 来快速体验这个方案吧。
最佳实践
前置准备: vscode
,vscode-tailwindcss
,nodejs lts
,微信开发者工具
1.通过vue-cli命令行创建工程
此部分内容见 uni-app快速上手
2.安装 npm 包
由于目前 uni-app
内置的 webpack
版本为 4
, postcss
版本为 7
我们需要安装 tailwindcss
的 postcss7-compat
版本:
yarn add -D weapp-tailwindcss-webpack-plugin postcss-rem-to-responsive-pixel tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
postcss-rem-to-responsive-pixel 是一个由笔者撰写的 postcss 插件,支持
rem
->rpx
,同时支持postcss7
和postcss8
,配置见此
3. 初始化 tailwind.config.js
和 postcss.config.js
只需要在初始化的文件内加入一些配置:
// tailwind.config.js 基础配置,无需任何preset
// https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/tailwind.config.js
/** @type {import('@types/tailwindcss/tailwind-config').TailwindConfig} */
module.exports = {
mode: 'jit',
purge: {
content: ['./src/**/*.{vue,js,ts,jsx,tsx,wxml}']
},
corePlugins: {
preflight: false
}
}
// postcss.config.js 参考示例
// https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/postcss.config.js
const path = require('path')
module.exports = {
parser: require('postcss-comment'),
plugins: [
require('postcss-import')({
resolve(id, basedir, importOptions) {
if (id.startsWith('~@/')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3))
} else if (id.startsWith('@/')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2))
} else if (id.startsWith('/') && !id.startsWith('//')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1))
}
return id
}
}),
require('autoprefixer')({
remove: process.env.UNI_PLATFORM !== 'h5'
}),
// #region 添加的部分开始
// tailwindcss for postcss7
require('tailwindcss')({ config: './tailwind.config.js' }),
// rem 转 rpx
require('postcss-rem-to-responsive-pixel/postcss7')({
rootValue: 32,
propList: ['*'],
transformUnit: 'rpx'
}),
// #endregion 添加的部分结束
require('@dcloudio/vue-cli-plugin-uni/packages/postcss')
]
}
4. 设置环境变量
添加 .env
设置 TAILWIND_MODE
# https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/.env
# jit 模式 HMR
TAILWIND_MODE=watch
这是为了兼容 tailwindcss v2
的 HMR 方案,如果你是用的是 tailwindcss v3
就不需要了。
5. 在 src/App.vue
中引用:
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
//...
})
</script>
<style lang="scss">
/*每个页面公共css */
// scss 需要安装 yarn add -D sass sass-loader@^10
// 小程序需要 'base' 来注入变量,但不需要 html preflight
// @tailwind base;
// @tailwind utilities;
@import 'tailwindcss/base';
@import 'tailwindcss/utilities';
</style>
6. 在根目录下添加 vue.config.js
// vue.config.js
const { UniAppWeappTailwindcssWebpackPluginV4 } = require('weapp-tailwindcss-webpack-plugin')
/**
* @type {import('@vue/cli-service').ProjectOptions}
*/
const config = {
//....
configureWebpack: {
plugins: [new UniAppWeappTailwindcssWebpackPluginV4()]
}
//....
}
module.exports = config
现在,您就可以在 uni-app
中使用 jit
的大部分特性了!
jit example
vue / wxml
<view :class="[flag?'bg-red-900':'bg-[#fafa00]']">bg-[#fafa00]</view>
<view :class="{'bg-[#098765]':flag===true}">bg-[#098765]</view>
<view class="p-[20px] -mt-2 mb-[-20px] ">p-[20px] -mt-2 mb-[-20px] margin的jit 不能这么写 -m-[20px]</view>
<view class="space-y-[1.6rem]">
<view class="w-[300rpx] text-black text-opacity-[0.19]">w-[300rpx] text-black text-opacity-[0.19]</view>
<view class="min-w-[300rpx] max-h-[100px] text-[20px] leading-[0.9]">min-w-[300rpx] max-h-[100px] text-[20px] leading-[0.9]</view>
<view class="max-w-[300rpx] min-h-[100px] text-[#dddddd]">max-w-[300rpx] min-h-[100px] text-[#dddddd]</view>
<view class="flex items-center justify-center h-[100px] w-[100px] rounded-[40px] bg-[#123456] bg-opacity-[0.54] text-[#ffffff]">Hello</view>
<view class="border-[10px] border-[#098765] border-solid border-opacity-[0.44]">border-[10px] border-[#098765] border-solid border-opacity-[0.44]</view>
<view class="grid grid-cols-3 divide-x-[10px] divide-[#010101] divide-solid">
<view>1</view>
<view>2</view>
<view>3</view>
</view>
</view>
or @apply
<template><view class="hello">world</view></template>
<style lang="scss">
.hello {
@apply flex items-center justify-center h-[100px] w-[100px] rounded-[40px] bg-[#123456] bg-opacity-[0.54] text-[#ffffff] #{!important};
}
</style>
了解更多
上述只是一个简单的 hello world
,想要了解更多,可以到 Github,欢迎 star
/fork
。
Bugs & Issues
如果在使用过程中遇到 Bugs 或者提出问题,欢迎提交到此处,笔者会尽快复现并修改
让小程序开发进入 tailwind jit
时代!
把
tailwindcss JIT
思想带入小程序开发吧!
笔者几个月前写了一个 tailwindcss-miniprogram-preset 预设,可是这个预设方案,可操作性非常的小,也不能兼容 tailwindcss v2/v3
的 Just in time
引擎,同时在写法上也有一定的变体。
于是笔者又设计了一个方案,并最终实现了 weapp-tailwindcss-webpack-plugin
。相比原先 preset
or postcss
方案,这个方案有很多的优势:
- 为
jit
设计,兼容v2/v3
2个版本的jit
引擎 - 开发者不需要额外记忆任何的写法变体,带来原汁原味的
tailwindcss
开发体验 - 兼容基于
webpack v4/v5
的小程序多端开发框架,简单易用
那么接下来就来展示一个基于 uni-app
的 demo 来快速体验这个方案吧。
最佳实践
前置准备: vscode
,vscode-tailwindcss
,nodejs lts
,微信开发者工具
1.通过vue-cli命令行创建工程
此部分内容见 uni-app快速上手
2.安装 npm 包
由于目前 uni-app
内置的 webpack
版本为 4
, postcss
版本为 7
我们需要安装 tailwindcss
的 postcss7-compat
版本:
yarn add -D weapp-tailwindcss-webpack-plugin postcss-rem-to-responsive-pixel tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
postcss-rem-to-responsive-pixel 是一个由笔者撰写的 postcss 插件,支持
rem
->rpx
,同时支持postcss7
和postcss8
,配置见此
3. 初始化 tailwind.config.js
和 postcss.config.js
只需要在初始化的文件内加入一些配置:
// tailwind.config.js 基础配置,无需任何preset
// https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/tailwind.config.js
/** @type {import('@types/tailwindcss/tailwind-config').TailwindConfig} */
module.exports = {
mode: 'jit',
purge: {
content: ['./src/**/*.{vue,js,ts,jsx,tsx,wxml}']
},
corePlugins: {
preflight: false
}
}
// postcss.config.js 参考示例
// https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/postcss.config.js
const path = require('path')
module.exports = {
parser: require('postcss-comment'),
plugins: [
require('postcss-import')({
resolve(id, basedir, importOptions) {
if (id.startsWith('~@/')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3))
} else if (id.startsWith('@/')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2))
} else if (id.startsWith('/') && !id.startsWith('//')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1))
}
return id
}
}),
require('autoprefixer')({
remove: process.env.UNI_PLATFORM !== 'h5'
}),
// #region 添加的部分开始
// tailwindcss for postcss7
require('tailwindcss')({ config: './tailwind.config.js' }),
// rem 转 rpx
require('postcss-rem-to-responsive-pixel/postcss7')({
rootValue: 32,
propList: ['*'],
transformUnit: 'rpx'
}),
// #endregion 添加的部分结束
require('@dcloudio/vue-cli-plugin-uni/packages/postcss')
]
}
4. 设置环境变量
添加 .env
设置 TAILWIND_MODE
# https://github.com/sonofmagic/weapp-tailwindcss-webpack-plugin/blob/main/demo/uni-app/.env
# jit 模式 HMR
TAILWIND_MODE=watch
这是为了兼容 tailwindcss v2
的 HMR 方案,如果你是用的是 tailwindcss v3
就不需要了。
5. 在 src/App.vue
中引用:
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
//...
})
</script>
<style lang="scss">
/*每个页面公共css */
// scss 需要安装 yarn add -D sass sass-loader@^10
// 小程序需要 'base' 来注入变量,但不需要 html preflight
// @tailwind base;
// @tailwind utilities;
@import 'tailwindcss/base';
@import 'tailwindcss/utilities';
</style>
6. 在根目录下添加 vue.config.js
// vue.config.js
const { UniAppWeappTailwindcssWebpackPluginV4 } = require('weapp-tailwindcss-webpack-plugin')
/**
* @type {import('@vue/cli-service').ProjectOptions}
*/
const config = {
//....
configureWebpack: {
plugins: [new UniAppWeappTailwindcssWebpackPluginV4()]
}
//....
}
module.exports = config
现在,您就可以在 uni-app
中使用 jit
的大部分特性了!
jit example
vue / wxml
<view :class="[flag?'bg-red-900':'bg-[#fafa00]']">bg-[#fafa00]</view>
<view :class="{'bg-[#098765]':flag===true}">bg-[#098765]</view>
<view class="p-[20px] -mt-2 mb-[-20px] ">p-[20px] -mt-2 mb-[-20px] margin的jit 不能这么写 -m-[20px]</view>
<view class="space-y-[1.6rem]">
<view class="w-[300rpx] text-black text-opacity-[0.19]">w-[300rpx] text-black text-opacity-[0.19]</view>
<view class="min-w-[300rpx] max-h-[100px] text-[20px] leading-[0.9]">min-w-[300rpx] max-h-[100px] text-[20px] leading-[0.9]</view>
<view class="max-w-[300rpx] min-h-[100px] text-[#dddddd]">max-w-[300rpx] min-h-[100px] text-[#dddddd]</view>
<view class="flex items-center justify-center h-[100px] w-[100px] rounded-[40px] bg-[#123456] bg-opacity-[0.54] text-[#ffffff]">Hello</view>
<view class="border-[10px] border-[#098765] border-solid border-opacity-[0.44]">border-[10px] border-[#098765] border-solid border-opacity-[0.44]</view>
<view class="grid grid-cols-3 divide-x-[10px] divide-[#010101] divide-solid">
<view>1</view>
<view>2</view>
<view>3</view>
</view>
</view>
or @apply
<template><view class="hello">world</view></template>
<style lang="scss">
.hello {
@apply flex items-center justify-center h-[100px] w-[100px] rounded-[40px] bg-[#123456] bg-opacity-[0.54] text-[#ffffff] #{!important};
}
</style>
了解更多
上述只是一个简单的 hello world
,想要了解更多,可以到 Github,欢迎 star
/fork
。
Bugs & Issues
如果在使用过程中遇到 Bugs 或者提出问题,欢迎提交到此处,笔者会尽快复现并修改
收起阅读 »
IDE may already started at port xxxx, trying to connect
-
1关闭微信开发者工具,然后检查APPID换成自己的APPID
-
2先关闭再打开自己的端口号(微信开发者工具——>设置——>安全设置——>安全(服务端口号))
-
3在HBuilder X的项目>unpackage>dist>dev>project.config.json文件里面添加下面代码,保存运行即可。
"miniprogramRoot": "./unpackage/dist/dev/mp-weixin", -
我是这样子通过的 ,可以留言联系我
-
1关闭微信开发者工具,然后检查APPID换成自己的APPID
-
2先关闭再打开自己的端口号(微信开发者工具——>设置——>安全设置——>安全(服务端口号))
-
3在HBuilder X的项目>unpackage>dist>dev>project.config.json文件里面添加下面代码,保存运行即可。
"miniprogramRoot": "./unpackage/dist/dev/mp-weixin", -
我是这样子通过的 ,可以留言联系我

使用uni-app开发微信小程序,若从vue2迁移到vue3,有几个地方需要修改
使用uni-app开发微信小程序,若从vue2迁移到vue3,有几个地方需要修改。
- 事先声明:以下仅代表我个人观点,所有问题均来自本人亲身经历。
- 开发工具:HBuilder X 3.3.10.20220124
1、创建应用的方式要改。main.js内容如下所示:
import store from '@/store'
import { createSSRApp } from 'vue'
export function createApp () {
// 创建应用
const app = createSSRApp(App)
// 使用app.component方法绑定全局组件
// 使用app.config.globalProperties属性绑定全局方法
// 使用store
app.use(store)
// 导出应用
return { app }
}
2、全局组件的注册,需要修改。需要注册到app上。以前是直接注册到Vue上。示例如下所示:
import BaseCopyright from '@/components/BaseCopyright'
app.component('BaseCopyright', BaseCopyright)
- 上面的BaseCopyright组件会生效。
- 注:亲测发现,在uni-app中,组件需要写成单文件组件,如果写成template的形式则组件不生效。
- 下面的GlobalComponentName组件不会生效。
app.component('GlobalComponentName', { template: `<view>GlobalComponentName</view>` })
3、创建store的方式要改且vuex需要使用"vuex": "^4.0.0-0"
版本。store.js内容如下所示:
import { createStore } from 'vuex'
export default createStore({
state: {},
mutations: {},
actions: {},
modules: {}
})
- 注:选择vue版本为2时,在uni-app中,不能在模板里直接使用store,需要使用computed中转一下。此时开发者工具appData中展示的数据是给人看的(展示完整的键名)。
- 注:选择vue版本为3时,在uni-app中,能在模板里直接使用store。此时开发者工具appData中展示的数据不是给人看的(展示a、b、c、d、e等被简化后的键)。
4、scss问题 - 和dart-sass
版本以及vite
打包工具多少有点关系。
- 路径需要拼全,index不能省,后缀也不能缺,否则会报错。
- 选择vue版本为2时,可以这么用:
~@/scss/config
。 - 选择vue版本为3时,必须这么用:
~@/scss/config/index.scss
。
- 选择vue版本为2时,可以这么用:
- 不能直接使用
/
进行除法,需要使用math.div
。
5、js问题 - 和打包工具换成vite
以及选择vue版本为3
多少有点关系。
- 不能使用
module.exports = {}
进行导出。需要使用export default {}
进行导出。- 第三方组件中亦如此,
mp-html
组件中的module.exports
需要更换为export default
。
- 第三方组件中亦如此,
- api响应的数据发生了变更,以前返回一个数组,第一个值是出错信息,第二个值是响应结果。现在直接返回响应结果,而错误信息需要用catch捕获。
- 这个有点坑,需要改的地方有点多。
- 选择vue版本为2时,在uni-app中,可以直接使用
Vue.prototype.$sleep
进行方法的绑定。- vue3需要使用
app.config.globalProperties.$sleep
进行方法的绑定。
- vue3需要使用
- 类似
:visible.sync
的用法,需要统一更换为,类似v-model:visible
的用法。
6、第三方组件mp-html无法正常使用,需要做如下改动:
- PR:https://github.com/jin-yufeng/mp-html/pull/398
- 1、
parse.js
中module.exports = Parser
更改为export default Parser
。 - 2、
mp-html.vue
中const Parser = require('./parser')
更改为import Parser from './parser'
。 - 3、
node.vue
中wxs
相关的代码转移到js
中。node.vue
中handler.use
别忘了更换为转移后的方法。
使用uni-app开发微信小程序,若从vue2迁移到vue3,有几个地方需要修改。
- 事先声明:以下仅代表我个人观点,所有问题均来自本人亲身经历。
- 开发工具:HBuilder X 3.3.10.20220124
1、创建应用的方式要改。main.js内容如下所示:
import store from '@/store'
import { createSSRApp } from 'vue'
export function createApp () {
// 创建应用
const app = createSSRApp(App)
// 使用app.component方法绑定全局组件
// 使用app.config.globalProperties属性绑定全局方法
// 使用store
app.use(store)
// 导出应用
return { app }
}
2、全局组件的注册,需要修改。需要注册到app上。以前是直接注册到Vue上。示例如下所示:
import BaseCopyright from '@/components/BaseCopyright'
app.component('BaseCopyright', BaseCopyright)
- 上面的BaseCopyright组件会生效。
- 注:亲测发现,在uni-app中,组件需要写成单文件组件,如果写成template的形式则组件不生效。
- 下面的GlobalComponentName组件不会生效。
app.component('GlobalComponentName', { template: `<view>GlobalComponentName</view>` })
3、创建store的方式要改且vuex需要使用"vuex": "^4.0.0-0"
版本。store.js内容如下所示:
import { createStore } from 'vuex'
export default createStore({
state: {},
mutations: {},
actions: {},
modules: {}
})
- 注:选择vue版本为2时,在uni-app中,不能在模板里直接使用store,需要使用computed中转一下。此时开发者工具appData中展示的数据是给人看的(展示完整的键名)。
- 注:选择vue版本为3时,在uni-app中,能在模板里直接使用store。此时开发者工具appData中展示的数据不是给人看的(展示a、b、c、d、e等被简化后的键)。
4、scss问题 - 和dart-sass
版本以及vite
打包工具多少有点关系。
- 路径需要拼全,index不能省,后缀也不能缺,否则会报错。
- 选择vue版本为2时,可以这么用:
~@/scss/config
。 - 选择vue版本为3时,必须这么用:
~@/scss/config/index.scss
。
- 选择vue版本为2时,可以这么用:
- 不能直接使用
/
进行除法,需要使用math.div
。
5、js问题 - 和打包工具换成vite
以及选择vue版本为3
多少有点关系。
- 不能使用
module.exports = {}
进行导出。需要使用export default {}
进行导出。- 第三方组件中亦如此,
mp-html
组件中的module.exports
需要更换为export default
。
- 第三方组件中亦如此,
- api响应的数据发生了变更,以前返回一个数组,第一个值是出错信息,第二个值是响应结果。现在直接返回响应结果,而错误信息需要用catch捕获。
- 这个有点坑,需要改的地方有点多。
- 选择vue版本为2时,在uni-app中,可以直接使用
Vue.prototype.$sleep
进行方法的绑定。- vue3需要使用
app.config.globalProperties.$sleep
进行方法的绑定。
- vue3需要使用
- 类似
:visible.sync
的用法,需要统一更换为,类似v-model:visible
的用法。
6、第三方组件mp-html无法正常使用,需要做如下改动:
- PR:https://github.com/jin-yufeng/mp-html/pull/398
- 1、
parse.js
中module.exports = Parser
更改为export default Parser
。 - 2、
mp-html.vue
中const Parser = require('./parser')
更改为import Parser from './parser'
。 - 3、
node.vue
中wxs
相关的代码转移到js
中。node.vue
中handler.use
别忘了更换为转移后的方法。

vue3下使用schema2code生成的 uni-file-picker 不兼容问题
"avatar": {
"bsonType": "file",
"fileMediaType": "image",
"description": "缩略图地址",
"label": "封面大图",
"title": "封面大图",
"trim": "both",
}
vue3下
<uni-file-picker v-if="item.avatar && item.avatar.fileType == 'image'
** " :value="item.avatar" **:file-mediatype="item.avatar && item.avatar.fileType" return-type="object"
:imageStyles="imageStyles" readonly></uni-file-picker>
<uni-link v-else :href="item.avatar && item.avatar.url" :text="item.avatar && item.avatar.url"></uni-link>
改为
:modelValue="item.avatar"
或者 在schema下做兼容
"componentForEdit": {
"props": {
":modelValue": "item.avatar" //兼容v3
}
},
"componentForShow": {
"props": {
":modelValue": "item.avatar" //兼容v3
}
}
"avatar": {
"bsonType": "file",
"fileMediaType": "image",
"description": "缩略图地址",
"label": "封面大图",
"title": "封面大图",
"trim": "both",
}
vue3下
<uni-file-picker v-if="item.avatar && item.avatar.fileType == 'image'
** " :value="item.avatar" **:file-mediatype="item.avatar && item.avatar.fileType" return-type="object"
:imageStyles="imageStyles" readonly></uni-file-picker>
<uni-link v-else :href="item.avatar && item.avatar.url" :text="item.avatar && item.avatar.url"></uni-link>
改为
:modelValue="item.avatar"
或者 在schema下做兼容
"componentForEdit": {
"props": {
":modelValue": "item.avatar" //兼容v3
}
},
"componentForShow": {
"props": {
":modelValue": "item.avatar" //兼容v3
}
}
收起阅读 »

iOS8 hash路由模式下页面循环reload解决方案
问题描述
h5页面在设置路由模式为hash时,iOS8设备打开页面会反复刷新。
详情请参考:issue - H5 hash路由模式下,iOS8页面加载无限reload
问题定位
- 在uniapp h5相关源码中搜索reload方法的调用,打log,确认到具体代码
- 查看源码发现是用了vue-router来稍加改造
- 提出问题:为什么别的机器不会反复刷新
- 了解popstate事件触发的逻辑:某些版本的浏览器内核会在页面加载完成后触发一次popstate事件,参考MDN文档
- 确认是页面加载完成后自动触发popstate,导致uniapp误处理触发页面reload
hack解决
解决思路:hack reload方法,识别该次异常的reload(load,popstate,reload短时间内连续触发),忽略该次reload。
相关代码:直接写入html文件即可,目前项目内就是这样解决
<script>
// @NOTE 处理uniapp路由bug,load,popstate,reload短时间内依次触发时,忽略这次reload
var reloadHackRecord = {};
window.addEventListener('load', function(e) {
reloadHackRecord.load = new Date().getTime();
});
var onPopState = function() {
reloadHackRecord.popstate = new Date().getTime();
window.removeEventListener('popstate', onPopState);
}
window.addEventListener('popstate', onPopState);
var oldReload = window.location.reload;
window.location.reload = function() {
var load = reloadHackRecord.load;
var popstate = reloadHackRecord.popstate;
var reload = new Date().getTime();
var margin = 100; // 经验值
if (load && popstate && reload && reload > popstate && popstate > load && reload - popstate < margin && popstate - load < margin) {
window.location.reload = oldReload;
// @TODO 可以上报看看有多少量
return;
}
}
</script>
更多信息
今天升级到最新版本,新建模板项目来验证,依然存在问题
路由模式使用history没有该问题
问题描述
h5页面在设置路由模式为hash时,iOS8设备打开页面会反复刷新。
详情请参考:issue - H5 hash路由模式下,iOS8页面加载无限reload
问题定位
- 在uniapp h5相关源码中搜索reload方法的调用,打log,确认到具体代码
- 查看源码发现是用了vue-router来稍加改造
- 提出问题:为什么别的机器不会反复刷新
- 了解popstate事件触发的逻辑:某些版本的浏览器内核会在页面加载完成后触发一次popstate事件,参考MDN文档
- 确认是页面加载完成后自动触发popstate,导致uniapp误处理触发页面reload
hack解决
解决思路:hack reload方法,识别该次异常的reload(load,popstate,reload短时间内连续触发),忽略该次reload。
相关代码:直接写入html文件即可,目前项目内就是这样解决
<script>
// @NOTE 处理uniapp路由bug,load,popstate,reload短时间内依次触发时,忽略这次reload
var reloadHackRecord = {};
window.addEventListener('load', function(e) {
reloadHackRecord.load = new Date().getTime();
});
var onPopState = function() {
reloadHackRecord.popstate = new Date().getTime();
window.removeEventListener('popstate', onPopState);
}
window.addEventListener('popstate', onPopState);
var oldReload = window.location.reload;
window.location.reload = function() {
var load = reloadHackRecord.load;
var popstate = reloadHackRecord.popstate;
var reload = new Date().getTime();
var margin = 100; // 经验值
if (load && popstate && reload && reload > popstate && popstate > load && reload - popstate < margin && popstate - load < margin) {
window.location.reload = oldReload;
// @TODO 可以上报看看有多少量
return;
}
}
</script>
更多信息
今天升级到最新版本,新建模板项目来验证,依然存在问题
路由模式使用history没有该问题
收起阅读 »
vue3 setup页面传参
官方的文档确实写得不清楚,以前我们都用onLoad来接收参数。而使用 vue3 的script setup时怎么接收?也没有看到有说明(不明白文档为什么不多给一些示例)。下面的示例在H5上是没有问题的,不知道其它平台如何。
A页面
uni.navigateTo({
url: '../test?id=1'
})
test页面
const props = defineProps()
console.log(props) // {id: "1"}
官方的文档确实写得不清楚,以前我们都用onLoad来接收参数。而使用 vue3 的script setup时怎么接收?也没有看到有说明(不明白文档为什么不多给一些示例)。下面的示例在H5上是没有问题的,不知道其它平台如何。
A页面
uni.navigateTo({
url: '../test?id=1'
})
test页面
const props = defineProps()
console.log(props) // {id: "1"}
收起阅读 »

mitt 的 uni_modules 完美迁移版本
tob-mitt
在 vue3
中,mitt 是一个推荐的 eventBus
库。这是一个 uni_modules
的完美迁移版本。
插件市场
https://ext.dcloud.net.cn/plugin?id=7323
原仓库
Usage
import mitt from "@/uni_modules/tob-mitt/index.js"
// 注册两个指定类型的事件函数
mitt.on('foo', () => console.log('我是foo1'))
mitt.on('foo', () => console.log('我是foo2'))
// 触发该类型的事件函数
mitt.emit('foo') // 将打印 我是foo1,我是foo2
// 注册一个带形参的事件函数
mitt.on('bar', (msg) => console.log(msg))
// 触发事件函数的同时设置实参
mitt.emit('bar', '你好') // 将打印 你好
mitt.off('bar') // 卸载所有 bar 事件函数
const bar = () => console.log('我好')
mitt.on('bar', bar)
mitt.off('bar', bar) // 单独卸载该事件函数
mitt.emit('bar') // 因为被卸载了,所以什么都不会触发
// 注册所有类型的事件函数
mitt.on('*', () => {
console.log("不论什么时候都会触发")
})
mitt.emit('*') // 打印 不论什么时候都会触发
mitt.emit('foo') // 打印 我是foo1,我是foo2 不论什么时候都会触发
mitt.all // 保存事件函数的 map
组织
欢迎关注 帝莎编程
官网
Gitee
Github
网易云课堂
License
Made with markthree
Published under MIT License.
tob-mitt
在 vue3
中,mitt 是一个推荐的 eventBus
库。这是一个 uni_modules
的完美迁移版本。
插件市场
https://ext.dcloud.net.cn/plugin?id=7323
原仓库
Usage
import mitt from "@/uni_modules/tob-mitt/index.js"
// 注册两个指定类型的事件函数
mitt.on('foo', () => console.log('我是foo1'))
mitt.on('foo', () => console.log('我是foo2'))
// 触发该类型的事件函数
mitt.emit('foo') // 将打印 我是foo1,我是foo2
// 注册一个带形参的事件函数
mitt.on('bar', (msg) => console.log(msg))
// 触发事件函数的同时设置实参
mitt.emit('bar', '你好') // 将打印 你好
mitt.off('bar') // 卸载所有 bar 事件函数
const bar = () => console.log('我好')
mitt.on('bar', bar)
mitt.off('bar', bar) // 单独卸载该事件函数
mitt.emit('bar') // 因为被卸载了,所以什么都不会触发
// 注册所有类型的事件函数
mitt.on('*', () => {
console.log("不论什么时候都会触发")
})
mitt.emit('*') // 打印 不论什么时候都会触发
mitt.emit('foo') // 打印 我是foo1,我是foo2 不论什么时候都会触发
mitt.all // 保存事件函数的 map
组织
欢迎关注 帝莎编程
官网
Gitee
Github
网易云课堂
License
Made with markthree
Published under MIT License.
收起阅读 »
可以将通用的 uniapp-api 转换为 composition-api 的工具
tob-hook-wrap
可以将通用的 uniapp-api 转换为 composition-api 的工具
动机
在开发过程中,uniapp-api
的回调形式在 vue3
可以用更加简洁的方式来表达,同时赋予更灵活的操作。
只要需要 success
, fail
, complete
的 uniapp-api
就可以转换为更简单的 composition-api
。
success
的结果会被设置到result.value
fail
的结果会被设置到error.value
- 函数的执行加载状态将被设置到
loading.vue
例如 uni.request
// 原生
uni.request({
url: '...',
data: {
name: '张三',
age: 18
},
success(data) {
console.log(data) // 数据
},
fail(error) {
console.log(error) // 错误
},
complete() {
console.log(false) // loading 结束
}
})
// 现在
const { result, error, loading } = useRequest({
url: '...',
data: {
name: '张三',
age: 18
}
})
例子
1. useRequest
// composables/request.js
import { $U } from "@/uni_modules/tob-use-wrap/index.js"
export const useRequest = $U(uni.request)
<!-- 页面中 -->
<template>
<view>
<view>数据结果: {{result}}</view>
<view>加载状态: {{loading}}</view>
<view>错误信息: {{error}}</view>
</view>
</template>
<script>
import { useRequest } from "@/composables/request.js"
export default {
setup() {
const { result, loading, error } = useRequest({
url: '...',
data: {
age: 18,
name: '张三'
}
})
return {
result, // 数据结果
error, // 错误信息
loading // 加载状态
}
}
}
</script>
<br />
2. useUploadFile
// composables/uploadFile.js
import { watch } from "vue"
import { $U } from "@/uni_modules/tob-use-wrap/index.js"
export const useUploadFile = $U(uni.uploadFile)
<!-- 页面中 -->
<template>
<view>
<view>上传结果: {{result}}</view>
<view>加载状态: {{loading}}</view>
<view>错误信息: {{error}}</view>
</view>
</template>
<script>
import { useUploadFile } from "@/composables/uploadFile.js"
export default {
setup() {
const { result, loading, error } = useUploadFile({
url: '...',
filePath: '...'
})
return {
result, // 上传结果
error, // 错误信息
loading // 加载状态
}
}
}
</script>
插件市场
https://ext.dcloud.net.cn/plugin?id=7318
传送门
tob-hook-wrap
可以将通用的 uniapp-api 转换为 composition-api 的工具
动机
在开发过程中,uniapp-api
的回调形式在 vue3
可以用更加简洁的方式来表达,同时赋予更灵活的操作。
只要需要 success
, fail
, complete
的 uniapp-api
就可以转换为更简单的 composition-api
。
success
的结果会被设置到result.value
fail
的结果会被设置到error.value
- 函数的执行加载状态将被设置到
loading.vue
例如 uni.request
// 原生
uni.request({
url: '...',
data: {
name: '张三',
age: 18
},
success(data) {
console.log(data) // 数据
},
fail(error) {
console.log(error) // 错误
},
complete() {
console.log(false) // loading 结束
}
})
// 现在
const { result, error, loading } = useRequest({
url: '...',
data: {
name: '张三',
age: 18
}
})
例子
1. useRequest
// composables/request.js
import { $U } from "@/uni_modules/tob-use-wrap/index.js"
export const useRequest = $U(uni.request)
<!-- 页面中 -->
<template>
<view>
<view>数据结果: {{result}}</view>
<view>加载状态: {{loading}}</view>
<view>错误信息: {{error}}</view>
</view>
</template>
<script>
import { useRequest } from "@/composables/request.js"
export default {
setup() {
const { result, loading, error } = useRequest({
url: '...',
data: {
age: 18,
name: '张三'
}
})
return {
result, // 数据结果
error, // 错误信息
loading // 加载状态
}
}
}
</script>
<br />
2. useUploadFile
// composables/uploadFile.js
import { watch } from "vue"
import { $U } from "@/uni_modules/tob-use-wrap/index.js"
export const useUploadFile = $U(uni.uploadFile)
<!-- 页面中 -->
<template>
<view>
<view>上传结果: {{result}}</view>
<view>加载状态: {{loading}}</view>
<view>错误信息: {{error}}</view>
</view>
</template>
<script>
import { useUploadFile } from "@/composables/uploadFile.js"
export default {
setup() {
const { result, loading, error } = useUploadFile({
url: '...',
filePath: '...'
})
return {
result, // 上传结果
error, // 错误信息
loading // 加载状态
}
}
}
</script>
插件市场
https://ext.dcloud.net.cn/plugin?id=7318
传送门