HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

让小程序开发进入 `tailwind jit` 时代!

Image

让小程序开发进入 tailwind jit 时代!

tailwindcss JIT 思想带入小程序开发吧!

笔者几个月前写了一个 tailwindcss-miniprogram-preset 预设,可是这个预设方案,可操作性非常的小,也不能兼容 tailwindcss v2/v3Just 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

我们需要安装 tailwindcsspostcss7-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,同时支持 postcss7postcss8配置见此

3. 初始化 tailwind.config.jspostcss.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 或者提出问题,欢迎提交到此处,笔者会尽快复现并修改

继续阅读 »

Image

让小程序开发进入 tailwind jit 时代!

tailwindcss JIT 思想带入小程序开发吧!

笔者几个月前写了一个 tailwindcss-miniprogram-preset 预设,可是这个预设方案,可操作性非常的小,也不能兼容 tailwindcss v2/v3Just 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

我们需要安装 tailwindcsspostcss7-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,同时支持 postcss7postcss8配置见此

3. 初始化 tailwind.config.jspostcss.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

HBuilderX 微信小程序
  • 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,有几个地方需要修改

微信小程序 vue3 uni_app

使用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
  • 不能直接使用/进行除法,需要使用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进行方法的绑定。
  • 类似:visible.sync的用法,需要统一更换为,类似v-model:visible的用法。

6、第三方组件mp-html无法正常使用,需要做如下改动:

  • PR:https://github.com/jin-yufeng/mp-html/pull/398
  • 1、parse.jsmodule.exports = Parser更改为export default Parser
  • 2、mp-html.vueconst Parser = require('./parser')更改为import Parser from './parser'
  • 3、node.vuewxs相关的代码转移到js中。
    • node.vuehandler.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
  • 不能直接使用/进行除法,需要使用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进行方法的绑定。
  • 类似:visible.sync的用法,需要统一更换为,类似v-model:visible的用法。

6、第三方组件mp-html无法正常使用,需要做如下改动:

  • PR:https://github.com/jin-yufeng/mp-html/pull/398
  • 1、parse.jsmodule.exports = Parser更改为export default Parser
  • 2、mp-html.vueconst Parser = require('./parser')更改为import Parser from './parser'
  • 3、node.vuewxs相关的代码转移到js中。
    • node.vuehandler.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解决方案

路由 iOS8

问题描述

h5页面在设置路由模式为hash时,iOS8设备打开页面会反复刷新。

详情请参考:issue - H5 hash路由模式下,iOS8页面加载无限reload

问题定位

  1. 在uniapp h5相关源码中搜索reload方法的调用,打log,确认到具体代码
  2. 查看源码发现是用了vue-router来稍加改造
  3. 提出问题:为什么别的机器不会反复刷新
  4. 了解popstate事件触发的逻辑:某些版本的浏览器内核会在页面加载完成后触发一次popstate事件,参考MDN文档
  5. 确认是页面加载完成后自动触发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

问题定位

  1. 在uniapp h5相关源码中搜索reload方法的调用,打log,确认到具体代码
  2. 查看源码发现是用了vue-router来稍加改造
  3. 提出问题:为什么别的机器不会反复刷新
  4. 了解popstate事件触发的逻辑:某些版本的浏览器内核会在页面加载完成后触发一次popstate事件,参考MDN文档
  5. 确认是页面加载完成后自动触发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没有该问题

收起阅读 »

开发了一款windows平台上传发布ipa的软件,感兴趣的可以试下,永久免费

windows ipa iOS

开发了一款windows平台上传发布ios app的软件,感兴趣的可以试下,永久免费。

软件名:WinIPAU
下载地址:http://ipau.tansanpi.cn

需要安装.net 6

苹果的接口访问比较慢,可能会出现失败的情况,可以多试几次,或者挂vpn

继续阅读 »

开发了一款windows平台上传发布ios app的软件,感兴趣的可以试下,永久免费。

软件名:WinIPAU
下载地址:http://ipau.tansanpi.cn

需要安装.net 6

苹果的接口访问比较慢,可能会出现失败的情况,可以多试几次,或者挂vpn

收起阅读 »

vue3 setup页面传参

vue3

官方的文档确实写得不清楚,以前我们都用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 完美迁移版本

vue3

tob-mitt

vue3 中,mitt 是一个推荐的 eventBus 库。这是一个 uni_modules 的完美迁移版本。

插件市场

https://ext.dcloud.net.cn/plugin?id=7323

原仓库

mitt

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

原仓库

mitt

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.

收起阅读 »

iOS APP

uni_app iOS

我是采用Vue编写,使用工具HbuilderX,XCode等。

答疑邮箱944522141@qq.com

我是采用Vue编写,使用工具HbuilderX,XCode等。

答疑邮箱944522141@qq.com

可以将通用的 uniapp-api 转换为 composition-api 的工具

vue3

tob-hook-wrap

可以将通用的 uniapp-api 转换为 composition-api 的工具

动机

在开发过程中,uniapp-api 的回调形式在 vue3 可以用更加简洁的方式来表达,同时赋予更灵活的操作。

只要需要 success, fail, completeuniapp-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, completeuniapp-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
传送门

收起阅读 »

webview 加载网络地址,侧滑返回,有需要的,联系

附件为视频演示

QQ:543610866

附件为视频演示

QQ:543610866