HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

python后端直接通过http的方式操作数据库, 不通过web控制台或者云函数

后端 数据库 python

只贴下python的insert数据库的操作, 其他语言类似
免费版的url = 'https://api.bspapp.com/client'
收费版的是url = 'https://api.next.bspapp.com/client'自己替换下

import requests  
import json  
import time  
import hmac  
import hashlib  

def insert():  
    # accessToken是后面header需要的参数  
    accessToken = get_access_token()  
    url = 'https://api.bspapp.com/client'  
    payload = {  
        'method': 'serverless.function.runtime.invoke',  
        'params': json.dumps(  
            {  
                "functionTarget": "DCloud-clientDB",  
                "functionArgs": {  
                    "command": {  
                        "$db": [  
                            {  
                                "$method": "collection",  
                                "$param": ["表名"]  
                            }, {  
                                "$method": "add",                        #如果是update这里add就换成update. 写法类似于mongodb的  
                                "$param": [{"字段名1": "字段值1"}]  
                            }  
                        ]  
                    }  
                }  
            }  
        ),  
        # spaceId自己在web控制台找, timestamp是时间戳  
        'spaceId': spaceId,  
        'timestamp': int(round(time.time() * 1000)),  
        'token': accessToken,  
    }  
    headers = {  
        'content-type': 'application/json',  
        'x-basement-token': accessToken,  
        'x-serverless-sign': get_sign(payload),  
    }  
    payload = json.dumps(payload)  
    # 发送post请求  
    response = requests.post(url, data=payload, headers=headers)  
    result = json.loads(response.text)  
    return result  

#获取access_token的方法, access_token一段时间会过期  
def get_access_token():  
     url = 'https://api.bspapp.com/client'  
     payload = {  
           'method': 'serverless.auth.user.anonymousAuthorize',  
            'params': '{}',  
            'spaceId': spaceId,  
            'timestamp': int(round(time.time() * 1000)),  
      }  
      headers = {  
             'Content-Type': 'application/json',  
              'x-serverless-sign': get_sign(payload)  
      }  

      payload = json.dumps(payload)  
      response = requests.post(url, data=payload, headers=headers)  
      result = json.loads(response.text)  

      access_token = result['data']['accessToken']  
      return access_token   

# 签名参数  
def get_sign(param):  
    #按照键名的升序排序  
    param = ksort(param)  
    #键与值 等号拼接的数组, 结果如["键1=值1", "键2=值2", "键3=值3"...]  
    signList = []  
    for k, v in param:  
        if v != '':  
            signList.append(k + '=' + str(v))  
    # 每个参数对拼接&并连在一起的字符串, 结果如 "键1=值1&键2=值2&键3=值3"...  
    signPars = '&'.join(signList)  
    #md5 hmac加密, clientSecret自己的web控制台里找, hmac, hashlib是python自带的库..其他语言也应该有类似的  
    sign = hmac.new(clientSecret.encode('utf-8'), signPars.encode('utf-8'), digestmod=hashlib.md5).hexdigest()  
    return sign  

#按照键名的升序排序, php里直接有ksort() 可以使用  
def ksort(d):  
    return [(k, d[k]) for k in sorted(d.keys())]  

下面是一些写法举例  
查询,比如查_id: 17的那条数据  
"command": {  
                        "$db": [  
                            {  
                                "$method": "collection",  
                                "$param": ["表名"]  
                            }, {  
                                "$method": "where",  
                                "$param": [{"_id": 17}]  
                            }, {  
                                "$method": "get",  
                                "$param": []  
                            }  
                        ]  
                    }  

删除, 比如删除_id: 17的那条数据  
"command": {  
                        "$db": [  
                            {  
                                "$method": "collection",  
                                "$param": ["表名"]  
                            }, {  
                                "$method": "where",  
                                "$param": [{"_id": 17}]  
                            }, {  
                                "$method": "remove",  
                                "$param": []  
                            }  
                        ]  
                    },  

改, 修改_id:17的那条数据  
"command": {  
                        "$db": [  
                            {  
                                "$method": "collection",  
                                "$param": ["表名"]  
                            }, {  
                                "$method": "where",  
                                "$param": [{"_id": 17]  
                            }, {  
                                "$method": "update",  
                                "$param": [{"字段1":"字段值1"}]  
                            }  
                        ]  
                    }
继续阅读 »

只贴下python的insert数据库的操作, 其他语言类似
免费版的url = 'https://api.bspapp.com/client'
收费版的是url = 'https://api.next.bspapp.com/client'自己替换下

import requests  
import json  
import time  
import hmac  
import hashlib  

def insert():  
    # accessToken是后面header需要的参数  
    accessToken = get_access_token()  
    url = 'https://api.bspapp.com/client'  
    payload = {  
        'method': 'serverless.function.runtime.invoke',  
        'params': json.dumps(  
            {  
                "functionTarget": "DCloud-clientDB",  
                "functionArgs": {  
                    "command": {  
                        "$db": [  
                            {  
                                "$method": "collection",  
                                "$param": ["表名"]  
                            }, {  
                                "$method": "add",                        #如果是update这里add就换成update. 写法类似于mongodb的  
                                "$param": [{"字段名1": "字段值1"}]  
                            }  
                        ]  
                    }  
                }  
            }  
        ),  
        # spaceId自己在web控制台找, timestamp是时间戳  
        'spaceId': spaceId,  
        'timestamp': int(round(time.time() * 1000)),  
        'token': accessToken,  
    }  
    headers = {  
        'content-type': 'application/json',  
        'x-basement-token': accessToken,  
        'x-serverless-sign': get_sign(payload),  
    }  
    payload = json.dumps(payload)  
    # 发送post请求  
    response = requests.post(url, data=payload, headers=headers)  
    result = json.loads(response.text)  
    return result  

#获取access_token的方法, access_token一段时间会过期  
def get_access_token():  
     url = 'https://api.bspapp.com/client'  
     payload = {  
           'method': 'serverless.auth.user.anonymousAuthorize',  
            'params': '{}',  
            'spaceId': spaceId,  
            'timestamp': int(round(time.time() * 1000)),  
      }  
      headers = {  
             'Content-Type': 'application/json',  
              'x-serverless-sign': get_sign(payload)  
      }  

      payload = json.dumps(payload)  
      response = requests.post(url, data=payload, headers=headers)  
      result = json.loads(response.text)  

      access_token = result['data']['accessToken']  
      return access_token   

# 签名参数  
def get_sign(param):  
    #按照键名的升序排序  
    param = ksort(param)  
    #键与值 等号拼接的数组, 结果如["键1=值1", "键2=值2", "键3=值3"...]  
    signList = []  
    for k, v in param:  
        if v != '':  
            signList.append(k + '=' + str(v))  
    # 每个参数对拼接&并连在一起的字符串, 结果如 "键1=值1&键2=值2&键3=值3"...  
    signPars = '&'.join(signList)  
    #md5 hmac加密, clientSecret自己的web控制台里找, hmac, hashlib是python自带的库..其他语言也应该有类似的  
    sign = hmac.new(clientSecret.encode('utf-8'), signPars.encode('utf-8'), digestmod=hashlib.md5).hexdigest()  
    return sign  

#按照键名的升序排序, php里直接有ksort() 可以使用  
def ksort(d):  
    return [(k, d[k]) for k in sorted(d.keys())]  

下面是一些写法举例  
查询,比如查_id: 17的那条数据  
"command": {  
                        "$db": [  
                            {  
                                "$method": "collection",  
                                "$param": ["表名"]  
                            }, {  
                                "$method": "where",  
                                "$param": [{"_id": 17}]  
                            }, {  
                                "$method": "get",  
                                "$param": []  
                            }  
                        ]  
                    }  

删除, 比如删除_id: 17的那条数据  
"command": {  
                        "$db": [  
                            {  
                                "$method": "collection",  
                                "$param": ["表名"]  
                            }, {  
                                "$method": "where",  
                                "$param": [{"_id": 17}]  
                            }, {  
                                "$method": "remove",  
                                "$param": []  
                            }  
                        ]  
                    },  

改, 修改_id:17的那条数据  
"command": {  
                        "$db": [  
                            {  
                                "$method": "collection",  
                                "$param": ["表名"]  
                            }, {  
                                "$method": "where",  
                                "$param": [{"_id": 17]  
                            }, {  
                                "$method": "update",  
                                "$param": [{"字段1":"字段值1"}]  
                            }  
                        ]  
                    }
收起阅读 »

【分享】微信内部浏览器跳转公众号引导用户关注

公众号

制作一个链接,点击该链接跳转到公众号关注页面。

1、从公众平台登进入公众号
2、点击开发>>开发者工具
3、F12 >>Elements
4、ctrl+f 搜索 uin_base64或在控制台window.wx.commonData.uin_base64
5、将下面链接的__biz=后面的值更换成uin_base64的值,然后用微信打开该链接即可。

https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=64位uin加密值&scene=110#wechat_redirect

示例:
https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzIzODU4NzkyOQ==&scene=110#wechat_redirect

继续阅读 »

制作一个链接,点击该链接跳转到公众号关注页面。

1、从公众平台登进入公众号
2、点击开发>>开发者工具
3、F12 >>Elements
4、ctrl+f 搜索 uin_base64或在控制台window.wx.commonData.uin_base64
5、将下面链接的__biz=后面的值更换成uin_base64的值,然后用微信打开该链接即可。

https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=64位uin加密值&scene=110#wechat_redirect

示例:
https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzIzODU4NzkyOQ==&scene=110#wechat_redirect

收起阅读 »

uniapp 打包时提示:未添加 OAuth 模块

OAuth

问题:打包时总是提示 “未添加 OAuth 模块”

关闭 manifest.json 模块配置中的 Oauth:在 manifest.json->App 模块配置中勾选 “OAuth(登录鉴权)”,但要将下方所有登录都取消勾选,

把 App.vue 中的一键登录 uni.preLogin 整个注释掉

login.vue 登录页中,注释掉第三方登录

继续阅读 »

问题:打包时总是提示 “未添加 OAuth 模块”

关闭 manifest.json 模块配置中的 Oauth:在 manifest.json->App 模块配置中勾选 “OAuth(登录鉴权)”,但要将下方所有登录都取消勾选,

把 App.vue 中的一键登录 uni.preLogin 整个注释掉

login.vue 登录页中,注释掉第三方登录

收起阅读 »

在开发unicloud+微信支付分账时遇到的奇葩问题和解决方案,原因未知渴望解答

微信支付

背景与需求

我负责开发运维的一款家政服务类小程序,支持微信在线支付,并在支付完成后,通过微信分账功能,将渠道环节的费用直接分账到渠道个人微信,例如,推荐人的分成直接到账。

理想与现实

理想

通过微信支付回调接口,触发分账,计算各个渠道的分账比例和金额,提交给微信,由微信完成分账。分账结果返回后,在平台做财务记录,完成分账。

现实

实际遇到的问题比想象的多出了很多,例如:
1,用户支付完成后立即发起分账申请,会失败,报错是验签失败(这根本和验签无关,是支付流程结束后等一段才能申请分账)
2,直接通过unicloud云函数A调用分账,不返回任何数据,云函数直接结束。(而如果通过另一个云函数B调用云函数A,则能正常返回数据)
3,如果在本地直接运行云函数B,调用云函数A,在支付完成后的大约1分钟后,可正常返回。但如果直接运行云函数A,则分账被执行,但不返回任何结果。
4,如果在云函数B中稍微代码多一点的位置调用云函数A,则会返回验签失败错误。如果在云函数B的靠前位置调用,则返回成功。
5,如果将云函数部署到云端,并通过设置外链方式触发云函数,则返回验签失败错误。但如果在本地hbuilderx里右键,本地运行,则正常。
6,如果在本地hbuilderx里右键云函数B,选择上传并运行,则返回验签失败错误。
7,在分账成功后,有时候不会立即返回分账成功的消息,分账状态是PROCESSING,因此需要过大约几分钟,调用查询分账的接口获取状态。但是,该接口必须在云函数A中直接执行,如果用其他函数调用,则返回验签失败错误。
8,如果设置云函数B为定时触发,在B中调用A,则正常。但如果选择访问链接方式触发云函数B,则大部分情况下是失败,偶尔成功。
9,发现对同一笔订单进行重复的分账,反而比get分账状态接口更好用。如果对同一笔订单再次申请分账,则会准确返回分账状态。
10,发现云函数B触发时的context不太一样,我将context强制定义成本地右键云函数本地运行方式才可正常返回分账结果。抓取方式是,云函数B中,event后面加,context,然后打印,再讲打印的结果,强行赋值给context,这样从任何地方访问,都会被认为是本地执行。

解决方案

1,建立云函数A,里面是分账代码。
2,建立云函数B,调用和执行云函数A,触发分账。
3,再次调用云函数B,再次对同一笔订单执行相同操作分账,可返回分账状态。
4,云函数B的触发方式很多,但只有两种(本地hbuilderx云函数右键本地运行和自动定时触发)不会报验签错误,而其中只有一种可部署到生产环境下,即定时触发。
5,阿里云限制云函数触发周期最短1小时,因此我建立了共6个云函数B,实现到了10分钟触发一次,云函数名额有限,只能临时采取这种方式了。

思考

我认为这种腾讯支付API不稳定的状态可能与发起提交的数据中的headers之类数据相关,要不然为什么相同的代码,本地运行可以,传到云函数运行就不行,或者定时触发可以,外链方式触发就不行,这些地方太诡异了。

打个广告

个人团队可承接微信小程序开发任务,定制各种疑难技术问题解决方案,V361757或私信即可。

继续阅读 »

背景与需求

我负责开发运维的一款家政服务类小程序,支持微信在线支付,并在支付完成后,通过微信分账功能,将渠道环节的费用直接分账到渠道个人微信,例如,推荐人的分成直接到账。

理想与现实

理想

通过微信支付回调接口,触发分账,计算各个渠道的分账比例和金额,提交给微信,由微信完成分账。分账结果返回后,在平台做财务记录,完成分账。

现实

实际遇到的问题比想象的多出了很多,例如:
1,用户支付完成后立即发起分账申请,会失败,报错是验签失败(这根本和验签无关,是支付流程结束后等一段才能申请分账)
2,直接通过unicloud云函数A调用分账,不返回任何数据,云函数直接结束。(而如果通过另一个云函数B调用云函数A,则能正常返回数据)
3,如果在本地直接运行云函数B,调用云函数A,在支付完成后的大约1分钟后,可正常返回。但如果直接运行云函数A,则分账被执行,但不返回任何结果。
4,如果在云函数B中稍微代码多一点的位置调用云函数A,则会返回验签失败错误。如果在云函数B的靠前位置调用,则返回成功。
5,如果将云函数部署到云端,并通过设置外链方式触发云函数,则返回验签失败错误。但如果在本地hbuilderx里右键,本地运行,则正常。
6,如果在本地hbuilderx里右键云函数B,选择上传并运行,则返回验签失败错误。
7,在分账成功后,有时候不会立即返回分账成功的消息,分账状态是PROCESSING,因此需要过大约几分钟,调用查询分账的接口获取状态。但是,该接口必须在云函数A中直接执行,如果用其他函数调用,则返回验签失败错误。
8,如果设置云函数B为定时触发,在B中调用A,则正常。但如果选择访问链接方式触发云函数B,则大部分情况下是失败,偶尔成功。
9,发现对同一笔订单进行重复的分账,反而比get分账状态接口更好用。如果对同一笔订单再次申请分账,则会准确返回分账状态。
10,发现云函数B触发时的context不太一样,我将context强制定义成本地右键云函数本地运行方式才可正常返回分账结果。抓取方式是,云函数B中,event后面加,context,然后打印,再讲打印的结果,强行赋值给context,这样从任何地方访问,都会被认为是本地执行。

解决方案

1,建立云函数A,里面是分账代码。
2,建立云函数B,调用和执行云函数A,触发分账。
3,再次调用云函数B,再次对同一笔订单执行相同操作分账,可返回分账状态。
4,云函数B的触发方式很多,但只有两种(本地hbuilderx云函数右键本地运行和自动定时触发)不会报验签错误,而其中只有一种可部署到生产环境下,即定时触发。
5,阿里云限制云函数触发周期最短1小时,因此我建立了共6个云函数B,实现到了10分钟触发一次,云函数名额有限,只能临时采取这种方式了。

思考

我认为这种腾讯支付API不稳定的状态可能与发起提交的数据中的headers之类数据相关,要不然为什么相同的代码,本地运行可以,传到云函数运行就不行,或者定时触发可以,外链方式触发就不行,这些地方太诡异了。

打个广告

个人团队可承接微信小程序开发任务,定制各种疑难技术问题解决方案,V361757或私信即可。

收起阅读 »

判断元素是否在于数组中

inArray (str, array) {  
    let isInArray = -1;  
    for (let i = 0; i < array.length; i++) {  
        let array_ = array[i];  
        if (isEqual(array_,str)) {  
            isInArray = i;  
            break;  
        };  
    };  
    return isInArray;  
}

isEqual() // 判断是否等于

.find() 是查找是否包含

继续阅读 »
inArray (str, array) {  
    let isInArray = -1;  
    for (let i = 0; i < array.length; i++) {  
        let array_ = array[i];  
        if (isEqual(array_,str)) {  
            isInArray = i;  
            break;  
        };  
    };  
    return isInArray;  
}

isEqual() // 判断是否等于

.find() 是查找是否包含

收起阅读 »

在 HBuilderX 中使用 tailwindcss

HBuilder HBuilderX

Image

在 HBuilderX 中使用 tailwindcss

之前我写了一个 weapp-tailwindcss-webpack-plugin 来兼容 uni-app,taro等等各个框架,不过那时候提供的 demo 都是 cli 版本的。最近社区里有同学问我, HBuilderX 要如何使用?

今天就给大家带来 HBuilderXvue2vue3 各自的 tailwindcss 的使用方法。

快速使用模板

如果你只想直接使用,而不在意 从 0 到 1 的搭建过程的话,你可以直接使用这 2 个模板。

uni-app-vue2-tailwind-hbuilder-template

uni-app-vue3-tailwind-hbuilder-template

下载下来后,先本地 npm i/yarn 安装一下依赖,然后就可以直接导入 HBuilderX 使用了。

从 0 到 1 的搭建过程

vue2 版本

vue2 版本的 uni-app 内置的 webpack 版本为 4 , postcss 版本为 7, 所以还是只能使用 @tailwindcss/postcss7-compat 版本。

package.json

新建一个vue2 uni-app项目,然后我们 npm init -y 在项目根目录创建一个 package.json,并安装依赖:

{  
  "devDependencies": {  
    "autoprefixer": "9",  
    "postcss": "7",  
    "postcss-rem-to-responsive-pixel": "^5.1.3",  
    "tailwindcss": "npm:@tailwindcss/postcss7-compat",  
    "weapp-tailwindcss-webpack-plugin": "^1.6.8",  
    "webpack": "npm:webpack@webpack-4"  
  }  
}

vue.config.js

然后添加 vue.config.js 文件,注册 weapp-tailwindcss-webpack-plugin:

// 为了 tailwindcss jit 开发时的热更新  
if (process.env.NODE_ENV === "development") {  
  process.env.TAILWIND_MODE = "watch";  
}  

const {  
  UniAppWeappTailwindcssWebpackPluginV4,  
} = require("weapp-tailwindcss-webpack-plugin");  

/**  
 * @type {import('@vue/cli-service').ProjectOptions}  
 */  
const config = {  
  //....  
  configureWebpack: {  
    plugins: [new UniAppWeappTailwindcssWebpackPluginV4()],  
  },  
  //....  
};  

module.exports = config;

postcss.config.js

然后再添加 postcss.config.js

const path = require("path");  

module.exports = {  
  plugins: [  
    require("autoprefixer")({  
      remove: process.env.UNI_PLATFORM !== "h5",  
    }),  
    require("tailwindcss")({  
      config: path.resolve(__dirname, "./tailwind.config.js"),  
    }),  
    // rem 转 rpx  
    require("postcss-rem-to-responsive-pixel/postcss7")({  
      rootValue: 32,  
      propList: ["*"],  
      transformUnit: "rpx",  
    }),  
  ],  
};

这里特别注意,在声明所有路径时,必须声明为绝对路径!!!

因为 hbuilderx 有这样一个读取配置的策略:如果目标目录是相对路径,就会读取 '\HBuilderX\plugins\uniapp-cli\' 目录下的文件,这直接导致配置找不到,导致项目无法启动。

tailwind.config.js

接着我们添加 tailwind.config.js

const path = require("path");  
const resolve = (p) => {  
  return path.resolve(__dirname, p);  
};  

/** @type {import('@types/tailwindcss/tailwind-config').TailwindConfig} */  
module.exports = {  
  mode: "jit",  
  purge: {  
    content: [  
      resolve("./index.html"),  
      resolve("./pages/**/*.{vue,js,ts,jsx,tsx,wxml}"),  
    ],  
  },  
  darkMode: false, // or 'media' or 'class'  
  theme: {  
    extend: {},  
  },  
  variants: {},  
  plugins: [],  
  corePlugins: {  
    preflight: false,  
  },  
};

同样,content 也必须为绝对路径。

App.vue 中引入 tailwindcss

最后只需在 App.vue 引入即可:

<style lang="scss">  
/*每个页面公共css */  
@import "tailwindcss/base";  
@import "tailwindcss/utilities";  
</style>

现在,你就可以在 hbuildervue2 项目中愉快的使用 tailwindcss 了!

vue3 版本

uni-appvue3/vite 版本,使用了 rollup base 的插件。
暂时不要升级到 vite 3.x 版本,目前 uni-app 并没有兼容这个版本,详见 Release Notes, 安装 2.x 版本的最新即可。(3.x会报process is not defined的错误)

package.json

我们 npm init -y 在项目根目录创建一个 package.json,并安装依赖:

{  
  "devDependencies": {  
    "autoprefixer": "^10.4.8",  
    "postcss": "^8.4.14",  
    "postcss-rem-to-responsive-pixel": "^5.1.3",  
    "tailwindcss": "^3.1.7",  
    "weapp-tailwindcss-webpack-plugin": "^1.6.10"  
  }  
}  

vite.config.js

然后添加 vite.config.js 文件,注册 weapp-tailwindcss-webpack-plugin:

import path from "path";  
import { defineConfig } from "vite";  
import uni from "@dcloudio/vite-plugin-uni";  
import vwt from "weapp-tailwindcss-webpack-plugin/vite";  
import postcssWeappTailwindcssRename from "weapp-tailwindcss-webpack-plugin/postcss";  

const isH5 = process.env.UNI_PLATFORM === "h5";  

// vite 插件配置,注意一定要把 uni 注册在 vwt 前  
const vitePlugins = [uni()];  

const resolve = (p) => {  
  return path.resolve(__dirname, p);  
};  

const postcssPlugins = [  
  require("autoprefixer")(),  
  require("tailwindcss")({  
    config: resolve("./tailwind.config.js"),  
  }),  
];  
if (!isH5) {  
  vitePlugins.push(vwt());  
  postcssPlugins.push(postcssWeappTailwindcssRename({}));  
}  
// https://vitejs.dev/config/  
export default defineConfig({  
  plugins: vitePlugins,  
  css: {  
    postcss: {  
      // 内联写法  
      plugins: postcssPlugins,  
    },  
  },  
});

tailwind.config.js

添加 tailwind.config.js:

const path = require("path");  
const resolve = (p) => {  
  return path.resolve(__dirname, p);  
};  
/** @type {import('tailwindcss').Config} */  
module.exports = {  
  content: ["./index.html", "./**/*.vue"].map(resolve),  
  theme: {  
    extend: {},  
  },  
  plugins: [],  
  corePlugins: {  
    preflight: false,  
  },  
};

下面这点在上面的 vue2 中也提到了,我再重复一遍

这里特别注意,在声明所有路径时,必须声明为绝对路径!!!

因为 hbuilderx 有这样一个读取配置的策略:如果目标目录是相对路径,就会读取 '\HBuilderX\plugins\uniapp-cli\' 目录下的文件,这直接导致配置找不到,导致项目无法启动。

App.vue 中引入 tailwindcss

<style lang="scss">  
/*每个页面公共css */  
@import "tailwindcss/base";  
@import "tailwindcss/utilities";  
</style>

现在,你就可以在 hbuilderxvue3 项目中愉快的使用 tailwindcss 了!

其他配置

.gitignore

unpackage  
node_modules  
.hbuilderx

HbuilderX 智能提示工具

DCloud-HBuilderX团队提供了对应的插件,可以去

https://ext.dcloud.net.cn/plugin?id=8560 进行下载,即可产生智能提示。

关联项目

插件核心

weapp-tailwindcss-webpack-plugin 提供核心转义功能

CLI 工具

weapp-ide-cli: 一个微信开发者工具命令行,快速方便的直接启动 ide 进行登录,开发,预览,上传代码等等功能。

模板 template

uni-app-vite-vue3-tailwind-vscode-template

uni-app-vue3-tailwind-vscode-template

uni-app-vue2-tailwind-vscode-template

weapp-native-mina-tailwindcss-template

uni-app-vue2-tailwind-hbuilder-template

uni-app-vue3-tailwind-hbuilder-template

预设 tailwindcss preset

tailwindcss-miniprogram-preset

Bugs & Issues

欢迎提交到此处

继续阅读 »

Image

在 HBuilderX 中使用 tailwindcss

之前我写了一个 weapp-tailwindcss-webpack-plugin 来兼容 uni-app,taro等等各个框架,不过那时候提供的 demo 都是 cli 版本的。最近社区里有同学问我, HBuilderX 要如何使用?

今天就给大家带来 HBuilderXvue2vue3 各自的 tailwindcss 的使用方法。

快速使用模板

如果你只想直接使用,而不在意 从 0 到 1 的搭建过程的话,你可以直接使用这 2 个模板。

uni-app-vue2-tailwind-hbuilder-template

uni-app-vue3-tailwind-hbuilder-template

下载下来后,先本地 npm i/yarn 安装一下依赖,然后就可以直接导入 HBuilderX 使用了。

从 0 到 1 的搭建过程

vue2 版本

vue2 版本的 uni-app 内置的 webpack 版本为 4 , postcss 版本为 7, 所以还是只能使用 @tailwindcss/postcss7-compat 版本。

package.json

新建一个vue2 uni-app项目,然后我们 npm init -y 在项目根目录创建一个 package.json,并安装依赖:

{  
  "devDependencies": {  
    "autoprefixer": "9",  
    "postcss": "7",  
    "postcss-rem-to-responsive-pixel": "^5.1.3",  
    "tailwindcss": "npm:@tailwindcss/postcss7-compat",  
    "weapp-tailwindcss-webpack-plugin": "^1.6.8",  
    "webpack": "npm:webpack@webpack-4"  
  }  
}

vue.config.js

然后添加 vue.config.js 文件,注册 weapp-tailwindcss-webpack-plugin:

// 为了 tailwindcss jit 开发时的热更新  
if (process.env.NODE_ENV === "development") {  
  process.env.TAILWIND_MODE = "watch";  
}  

const {  
  UniAppWeappTailwindcssWebpackPluginV4,  
} = require("weapp-tailwindcss-webpack-plugin");  

/**  
 * @type {import('@vue/cli-service').ProjectOptions}  
 */  
const config = {  
  //....  
  configureWebpack: {  
    plugins: [new UniAppWeappTailwindcssWebpackPluginV4()],  
  },  
  //....  
};  

module.exports = config;

postcss.config.js

然后再添加 postcss.config.js

const path = require("path");  

module.exports = {  
  plugins: [  
    require("autoprefixer")({  
      remove: process.env.UNI_PLATFORM !== "h5",  
    }),  
    require("tailwindcss")({  
      config: path.resolve(__dirname, "./tailwind.config.js"),  
    }),  
    // rem 转 rpx  
    require("postcss-rem-to-responsive-pixel/postcss7")({  
      rootValue: 32,  
      propList: ["*"],  
      transformUnit: "rpx",  
    }),  
  ],  
};

这里特别注意,在声明所有路径时,必须声明为绝对路径!!!

因为 hbuilderx 有这样一个读取配置的策略:如果目标目录是相对路径,就会读取 '\HBuilderX\plugins\uniapp-cli\' 目录下的文件,这直接导致配置找不到,导致项目无法启动。

tailwind.config.js

接着我们添加 tailwind.config.js

const path = require("path");  
const resolve = (p) => {  
  return path.resolve(__dirname, p);  
};  

/** @type {import('@types/tailwindcss/tailwind-config').TailwindConfig} */  
module.exports = {  
  mode: "jit",  
  purge: {  
    content: [  
      resolve("./index.html"),  
      resolve("./pages/**/*.{vue,js,ts,jsx,tsx,wxml}"),  
    ],  
  },  
  darkMode: false, // or 'media' or 'class'  
  theme: {  
    extend: {},  
  },  
  variants: {},  
  plugins: [],  
  corePlugins: {  
    preflight: false,  
  },  
};

同样,content 也必须为绝对路径。

App.vue 中引入 tailwindcss

最后只需在 App.vue 引入即可:

<style lang="scss">  
/*每个页面公共css */  
@import "tailwindcss/base";  
@import "tailwindcss/utilities";  
</style>

现在,你就可以在 hbuildervue2 项目中愉快的使用 tailwindcss 了!

vue3 版本

uni-appvue3/vite 版本,使用了 rollup base 的插件。
暂时不要升级到 vite 3.x 版本,目前 uni-app 并没有兼容这个版本,详见 Release Notes, 安装 2.x 版本的最新即可。(3.x会报process is not defined的错误)

package.json

我们 npm init -y 在项目根目录创建一个 package.json,并安装依赖:

{  
  "devDependencies": {  
    "autoprefixer": "^10.4.8",  
    "postcss": "^8.4.14",  
    "postcss-rem-to-responsive-pixel": "^5.1.3",  
    "tailwindcss": "^3.1.7",  
    "weapp-tailwindcss-webpack-plugin": "^1.6.10"  
  }  
}  

vite.config.js

然后添加 vite.config.js 文件,注册 weapp-tailwindcss-webpack-plugin:

import path from "path";  
import { defineConfig } from "vite";  
import uni from "@dcloudio/vite-plugin-uni";  
import vwt from "weapp-tailwindcss-webpack-plugin/vite";  
import postcssWeappTailwindcssRename from "weapp-tailwindcss-webpack-plugin/postcss";  

const isH5 = process.env.UNI_PLATFORM === "h5";  

// vite 插件配置,注意一定要把 uni 注册在 vwt 前  
const vitePlugins = [uni()];  

const resolve = (p) => {  
  return path.resolve(__dirname, p);  
};  

const postcssPlugins = [  
  require("autoprefixer")(),  
  require("tailwindcss")({  
    config: resolve("./tailwind.config.js"),  
  }),  
];  
if (!isH5) {  
  vitePlugins.push(vwt());  
  postcssPlugins.push(postcssWeappTailwindcssRename({}));  
}  
// https://vitejs.dev/config/  
export default defineConfig({  
  plugins: vitePlugins,  
  css: {  
    postcss: {  
      // 内联写法  
      plugins: postcssPlugins,  
    },  
  },  
});

tailwind.config.js

添加 tailwind.config.js:

const path = require("path");  
const resolve = (p) => {  
  return path.resolve(__dirname, p);  
};  
/** @type {import('tailwindcss').Config} */  
module.exports = {  
  content: ["./index.html", "./**/*.vue"].map(resolve),  
  theme: {  
    extend: {},  
  },  
  plugins: [],  
  corePlugins: {  
    preflight: false,  
  },  
};

下面这点在上面的 vue2 中也提到了,我再重复一遍

这里特别注意,在声明所有路径时,必须声明为绝对路径!!!

因为 hbuilderx 有这样一个读取配置的策略:如果目标目录是相对路径,就会读取 '\HBuilderX\plugins\uniapp-cli\' 目录下的文件,这直接导致配置找不到,导致项目无法启动。

App.vue 中引入 tailwindcss

<style lang="scss">  
/*每个页面公共css */  
@import "tailwindcss/base";  
@import "tailwindcss/utilities";  
</style>

现在,你就可以在 hbuilderxvue3 项目中愉快的使用 tailwindcss 了!

其他配置

.gitignore

unpackage  
node_modules  
.hbuilderx

HbuilderX 智能提示工具

DCloud-HBuilderX团队提供了对应的插件,可以去

https://ext.dcloud.net.cn/plugin?id=8560 进行下载,即可产生智能提示。

关联项目

插件核心

weapp-tailwindcss-webpack-plugin 提供核心转义功能

CLI 工具

weapp-ide-cli: 一个微信开发者工具命令行,快速方便的直接启动 ide 进行登录,开发,预览,上传代码等等功能。

模板 template

uni-app-vite-vue3-tailwind-vscode-template

uni-app-vue3-tailwind-vscode-template

uni-app-vue2-tailwind-vscode-template

weapp-native-mina-tailwindcss-template

uni-app-vue2-tailwind-hbuilder-template

uni-app-vue3-tailwind-hbuilder-template

预设 tailwindcss preset

tailwindcss-miniprogram-preset

Bugs & Issues

欢迎提交到此处

收起阅读 »

关于(.)点号(*)星号垂直居中的方法

css html HTML5

场景:在一段文字中,想要(.)点号上下居中显示。
方法一:
<span class="dot">.<span>
.dot{
display: inline-block;
vertical-align: middle;
width: auto;
height: 20px;
line-height: 10px;
}
注:这里的高度最好为父元素设置的行高。如果没有完全居中,可以微调一下行高。

方法二:
<span class="dot">高度&middot;高度</span>

<span class="dot">高度&bull;高度</span>

<span class="dot">高度&sdot;高度</span>
注:这里利用实体字符来实现一个上下居中的点,&sdot;和&middot;效果一样,&bull;是一个粗的点,
以此类推,实体符的*(&lowast;),也可以达到上下居中的效果。

继续阅读 »

场景:在一段文字中,想要(.)点号上下居中显示。
方法一:
<span class="dot">.<span>
.dot{
display: inline-block;
vertical-align: middle;
width: auto;
height: 20px;
line-height: 10px;
}
注:这里的高度最好为父元素设置的行高。如果没有完全居中,可以微调一下行高。

方法二:
<span class="dot">高度&middot;高度</span>

<span class="dot">高度&bull;高度</span>

<span class="dot">高度&sdot;高度</span>
注:这里利用实体字符来实现一个上下居中的点,&sdot;和&middot;效果一样,&bull;是一个粗的点,
以此类推,实体符的*(&lowast;),也可以达到上下居中的效果。

收起阅读 »

个人全职接单,时间充裕

外包 招聘

uniapp非常熟练
有商城、社交、地图、直播、音视频...相关案例
网站、管理系统、小程序、APP都可以
有需要请联系我 V:SUSU-HG

uniapp非常熟练
有商城、社交、地图、直播、音视频...相关案例
网站、管理系统、小程序、APP都可以
有需要请联系我 V:SUSU-HG

webpack学习经验总结

【声明】本文仅作经验分享,非任何性质教学或其他,如有错误欢迎评论区指出 :)

这里存放一些学习webpack配置的经验总结,也是方便自己以后取用 :)

推荐阅读文章:
webpack学习之webpack.config.js详解
module模块详解

拆分详解:
1、process.env属性开发环境

if (process.env.NODE_ENV == null) {  
    process.env.NODE_ENV = 'development';  
}

2、配置module
相关文章:
webpack中enforce的用法
webpack配置的一些要点
loader详解

在rules部分使用 loader 根据匹配规则打包除 JavaScript 之外的静态资源,为了契合模块化的代码整洁,这里做了单独的定义调用。

const moduleRules = [  
    {  
        test: /\.ts$/,  //匹配文件类型  
        enforce: 'pre', //处理顺序  
        loader: 'tslint-loader', //处理文件的loader类型  
    },  
    {  
        test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9] )?$/,  
        exclude: /loading.svg/,  
        use: [{  //同loader的详解  
            loader: 'file-loader',  //处理文件的loader类型  
            options: {  
                name: '[name].[ext]',  
                outputPath: 'popup/fonts/',  //用来存放打包后文件的输出目录  
                publicPath: './fonts/',  //指定资源文件引用的目录  
            },  
        }],  
    }  
];  

const config = {  
   module: { rules: moduleRules },  
};  

module.exports = config;

3、配置plugin
相关文章:
HtmlWebpackPlugin
MiniCssExtractPlugin
HtmlWebpackPlugin用法总结
如何正确使用sourcemap

同rules,做了单独的定义调用。

const plugins = [  
    new HtmlWebpackPlugin({  //将静态文件插入html  
        template: './src/popup/index.html',  
        filename: 'popup/index.html',  
        chunks: ['popup/polyfills', 'popup/vendor-angular', 'popup/vendor', 'popup/main'],  
        cache: false, // Remove after upgrading to Webpack 5  
    }),  
    new CopyWebpackPlugin({  //拷贝文件  
        patterns: [  
            './src/manifest.json',  
            { from: './src/_locales', to: '_locales' },  
            { from: './src/images', to: 'images' },  
            { from: './src/popup/images', to: 'popup/images' },  
            { from: './src/content/autofill.css', to: 'content' },  
        ]  
    }),  
    new webpack.SourceMapDevToolPlugin({  //devtool  
        include: ['popup/main.js', 'background.js'],  
    }),  
    new MiniCssExtractPlugin({ //为每个包含 CSS 的 JS 文件创建一个单独的 CSS 文件  
        filename: '[name].css',  
        chunkFilename: 'chunk-[id].css',  
    }),  
    new webpack.DefinePlugin({  
        'process.env': {  
            'ENV': JSON.stringify(ENV)  
        }  
    }),  
    new AngularCompilerPlugin({  
        tsConfigPath: 'tsconfig.json',  
        entryModule: 'src/popup/app.module#AppModule',  
        sourceMap: true,  
    }),  
    new CleanWebpackPlugin({  
        cleanAfterEveryBuildPatterns: ['!popup/fonts/**/*'],  
    }),  
];  

const config = {  
   plugins: plugins,,  
};
继续阅读 »

【声明】本文仅作经验分享,非任何性质教学或其他,如有错误欢迎评论区指出 :)

这里存放一些学习webpack配置的经验总结,也是方便自己以后取用 :)

推荐阅读文章:
webpack学习之webpack.config.js详解
module模块详解

拆分详解:
1、process.env属性开发环境

if (process.env.NODE_ENV == null) {  
    process.env.NODE_ENV = 'development';  
}

2、配置module
相关文章:
webpack中enforce的用法
webpack配置的一些要点
loader详解

在rules部分使用 loader 根据匹配规则打包除 JavaScript 之外的静态资源,为了契合模块化的代码整洁,这里做了单独的定义调用。

const moduleRules = [  
    {  
        test: /\.ts$/,  //匹配文件类型  
        enforce: 'pre', //处理顺序  
        loader: 'tslint-loader', //处理文件的loader类型  
    },  
    {  
        test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9] )?$/,  
        exclude: /loading.svg/,  
        use: [{  //同loader的详解  
            loader: 'file-loader',  //处理文件的loader类型  
            options: {  
                name: '[name].[ext]',  
                outputPath: 'popup/fonts/',  //用来存放打包后文件的输出目录  
                publicPath: './fonts/',  //指定资源文件引用的目录  
            },  
        }],  
    }  
];  

const config = {  
   module: { rules: moduleRules },  
};  

module.exports = config;

3、配置plugin
相关文章:
HtmlWebpackPlugin
MiniCssExtractPlugin
HtmlWebpackPlugin用法总结
如何正确使用sourcemap

同rules,做了单独的定义调用。

const plugins = [  
    new HtmlWebpackPlugin({  //将静态文件插入html  
        template: './src/popup/index.html',  
        filename: 'popup/index.html',  
        chunks: ['popup/polyfills', 'popup/vendor-angular', 'popup/vendor', 'popup/main'],  
        cache: false, // Remove after upgrading to Webpack 5  
    }),  
    new CopyWebpackPlugin({  //拷贝文件  
        patterns: [  
            './src/manifest.json',  
            { from: './src/_locales', to: '_locales' },  
            { from: './src/images', to: 'images' },  
            { from: './src/popup/images', to: 'popup/images' },  
            { from: './src/content/autofill.css', to: 'content' },  
        ]  
    }),  
    new webpack.SourceMapDevToolPlugin({  //devtool  
        include: ['popup/main.js', 'background.js'],  
    }),  
    new MiniCssExtractPlugin({ //为每个包含 CSS 的 JS 文件创建一个单独的 CSS 文件  
        filename: '[name].css',  
        chunkFilename: 'chunk-[id].css',  
    }),  
    new webpack.DefinePlugin({  
        'process.env': {  
            'ENV': JSON.stringify(ENV)  
        }  
    }),  
    new AngularCompilerPlugin({  
        tsConfigPath: 'tsconfig.json',  
        entryModule: 'src/popup/app.module#AppModule',  
        sourceMap: true,  
    }),  
    new CleanWebpackPlugin({  
        cleanAfterEveryBuildPatterns: ['!popup/fonts/**/*'],  
    }),  
];  

const config = {  
   plugins: plugins,,  
};
收起阅读 »

用uniapp编译chrome扩展程序(一)

【声明】本文仅作经验分享,非任何性质教学或其他,如有错误欢迎评论区指出 :)

目前进度:编译成h5后嵌入chrome扩展正常显示并运行。

限制及问题:
1、rpx无法识别,目前是手动修改为px;
2、嵌入后网页搜索页无法正常滑动,但不影响图片、咨询、详情页等;
3、仅成功复现app,无交互及网页识别;

由于限制1,编译前需要做出的改动:
1、app.vue文件css设置窗口大小

2、复现限制1步骤

编译后操作步骤:
1、使用HBX编译为h5包

2、手动添加mainfest.json在h5根目录
我的路径是 unpackage\dist\build\h5

manifest.json可参考我的简易版配置,manifest.json配置解析

{  
  "name": "项目名称",  
  "version": "1.0",  
  "manifest_version": 3,  
  "description": "项目描述",  
  "action":  
  {  
      "default_icon": {  
          "64":"static/res/icon/logo.png",  
          "72":"static/logo.png",  
          "144":"static/res/icon/login-logo.png"  
      },  
      "default_popup": "index.html",  
      "default_title":"抬头名称"  
  },  
  "icons": {  
      "64":"static/res/icon/logo.png",  
      "72":"static/logo.png",  
      "144":"static/res/icon/login-logo.png"  
    },  
    "content_scripts":  
    [  
        {  
            "matches": ["<all_urls>"],  
            "css": [""], //你编译出来的css路径  
            "run_at": "document_start"  
        }  
    ]  
}

3、修改index.html文件。
此处主要是由于chrome扩展插件的一些安全性考虑从而不支持内写script。 csp为什么拒绝内联


【仅作参考,如有更好的解决方法欢迎评论区指出 :)】

4、选中根目录添加 chrome扩展

5、成果

到目前为止,项目就在扩展程序上编译使用了。但仍需添加通信等功能,学会后再来分享,下篇见!

继续阅读 »

【声明】本文仅作经验分享,非任何性质教学或其他,如有错误欢迎评论区指出 :)

目前进度:编译成h5后嵌入chrome扩展正常显示并运行。

限制及问题:
1、rpx无法识别,目前是手动修改为px;
2、嵌入后网页搜索页无法正常滑动,但不影响图片、咨询、详情页等;
3、仅成功复现app,无交互及网页识别;

由于限制1,编译前需要做出的改动:
1、app.vue文件css设置窗口大小

2、复现限制1步骤

编译后操作步骤:
1、使用HBX编译为h5包

2、手动添加mainfest.json在h5根目录
我的路径是 unpackage\dist\build\h5

manifest.json可参考我的简易版配置,manifest.json配置解析

{  
  "name": "项目名称",  
  "version": "1.0",  
  "manifest_version": 3,  
  "description": "项目描述",  
  "action":  
  {  
      "default_icon": {  
          "64":"static/res/icon/logo.png",  
          "72":"static/logo.png",  
          "144":"static/res/icon/login-logo.png"  
      },  
      "default_popup": "index.html",  
      "default_title":"抬头名称"  
  },  
  "icons": {  
      "64":"static/res/icon/logo.png",  
      "72":"static/logo.png",  
      "144":"static/res/icon/login-logo.png"  
    },  
    "content_scripts":  
    [  
        {  
            "matches": ["<all_urls>"],  
            "css": [""], //你编译出来的css路径  
            "run_at": "document_start"  
        }  
    ]  
}

3、修改index.html文件。
此处主要是由于chrome扩展插件的一些安全性考虑从而不支持内写script。 csp为什么拒绝内联


【仅作参考,如有更好的解决方法欢迎评论区指出 :)】

4、选中根目录添加 chrome扩展

5、成果

到目前为止,项目就在扩展程序上编译使用了。但仍需添加通信等功能,学会后再来分享,下篇见!

收起阅读 »

NFC完整版、同步读与写、读取连接标签、查询NDEF状态、读写NDEF(ios)

NFC完整版、同步读与写、读取连接标签、查询NDEF状态、读写NDEF(ios) :https://ext.dcloud.net.cn/plugin?id=8903

NFC完整版、同步读与写、读取连接标签、查询NDEF状态、读写NDEF(ios) :https://ext.dcloud.net.cn/plugin?id=8903

cover-view有办法设成图片吗

发现cover-view添加文字,可以覆盖在video上,但是包图片不行,设背景图也不行

发现cover-view添加文字,可以覆盖在video上,但是包图片不行,设背景图也不行