
一个关于微信小程序《用户隐私保护指引》的自定义组件
<template>
<view v-if="innerShow" @touchmove.stop.prevent class="flex alcenter justify-center"
style="position: fixed;left:0;top:0;z-index:999;width:100vw;height:100vh;background-color: rgba(0,0,0,0.5);"
:style="{top:(scrollTop||0) 'px'}">
<view class="pd40 bdr16 bg-w">
<view class="mb20 text-center">
<text class="ft20 text-main ftwbold">{{title}}</text>
</view>
<scroll-view class="ft16" :scroll-y="true" style="max-height: 50vh;width: 75vw;">
<text class="text-info" space="nbsp"> {{desc1}}</text>
<text class="text-red" @tap="openPrivacyContract">{{urlTitle}}</text>
<text class="text-info">{{desc2}}</text>
</scroll-view>
<view class="mt40 flex alcenter justify-between">
<button style="margin:0" size="mini" id="disagree-btn" type="default" @tap="handleDisagree">不同意</button>
<button style="margin:0" size="mini" id="agree-btn" type="warn" open-type="agreePrivacyAuthorization"
@agreeprivacyauthorization="handleAgree">同意并继续</button>
</view>
</view>
</view>
</template>
<!-- 注:text-info、text-main、text-red为CSS::color -->
<script>
let privacyHandler
let privacyResolves = new Set()
let closeOtherPagePopUpHooks = new Set()
if (wx.onNeedPrivacyAuthorization) {
wx.onNeedPrivacyAuthorization(resolve => {
console.log('触发《用户隐私指引保护》弹窗 onNeedPrivacyAuthorization')
if (typeof privacyHandler === 'function') {
privacyHandler(resolve)
}
})
}
const closeOtherPagePopUp = (closePopUp) => {
closeOtherPagePopUpHooks.forEach(hook => {
if (closePopUp !== hook) {
hook()
}
})
}
export default {
name: "privacy-popup",
props: {
scrollTop: {
type: Number,
default: 0
},
isSingleCheck: { // 是否单次检查隐私同意状态,因为同意隐私后,代码默认会执行(回调)该页面中Set集合存储的所有隐私接口操作。如果页面中有多个隐私接口回调,可能导致程序异常。
type: Boolean,
default: false
}
},
data() {
return {
title: "用户隐私保护提示",
desc1: " 感谢您使用本小程序,依据法规,在您使用本小程序前应当阅读并同意",
urlTitle: "《用户隐私保护指引》",
desc2: "当您点击同意并开始使用产品服务时,即表示你已理解并同意该条款内容,该条款将对您产生法律约束力。如您拒绝,应当停止使用本小程序。",
innerShow: false
}
},
mounted() {
this.ponLoad(true)
},
destroyed() {
if (this.closePopUp) {
console.error("隐私组件已关闭[destroyed]")
closeOtherPagePopUpHooks.delete(this.closePopUp)
this.closePopUp = null
}
},
methods: {
ponLoad(isChildMounted =
false
) { // 因为一些页面(父组件)在生命周期onLoad时就调用隐私接口了,比这个隐私子组件的生命周期mounted早执行,所以要优先初始化弹出方法(父组件以$ref形式调用)。换个说法,在执行当前组件mounted之前调用隐私接口了的页面,需要提前执行this.$ref.privacyPopup?.ponLoad()以支持弹窗打开。
if (!this.closePopUp) {
console.error(`隐私组件已加载[${isChildMounted?'子mounted':'onLoad'}]`)
const closePopUp = () => {
this.disPopUp()
}
privacyHandler = resolve => {
if (this.isSingleCheck) {
privacyResolves.clear()
}
privacyResolves.add(resolve)
this.popUp()
// 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗
closeOtherPagePopUp(closePopUp)
}
this.closePopUp = closePopUp
closeOtherPagePopUpHooks.add(this.closePopUp)
}
},
ponUnload() { // 兼容tabBar页(onHide)与普通页(onUnload)跳转,使得再次访问页面时能够弹出弹出
if (this.closePopUp) {
console.error("隐私组件已关闭[onUnload]")
closeOtherPagePopUpHooks.delete(this.closePopUp)
this.closePopUp = null
}
},
ponHide() { // 兼容tabBar页(onHide)与tabBar页(onHide)跳转,使得再次访问页面时能够弹出弹出
if (this.closePopUp) {
console.error("隐私组件已关闭[onHide]")
closeOtherPagePopUpHooks.delete(this.closePopUp)
this.closePopUp = null
}
},
onDisagree() { // 点击不同意时,主动关闭
// if (this.closePopUp) {
// console.error("隐私组件已关闭[onDisagree]")
// closeOtherPagePopUpHooks.delete(this.closePopUp)
// this.closePopUp = null
// }
},
handleAgree(e) {
this.disPopUp()
// 这里演示了同时调用多个wx隐私接口时要如何处理:让隐私弹窗保持单例,点击一次同意按钮即可让所有pending中的wx隐私接口继续执行
privacyResolves.forEach(resolve => {
resolve({
event: 'agree',
buttonId: 'agree-btn'
})
})
privacyResolves.clear()
},
handleDisagree(e) {
this.disPopUp()
privacyResolves.forEach(resolve => {
resolve({
event: 'disagree',
})
})
privacyResolves.clear()
// this.onDisagree()
},
popUp() {
if (this.innerShow === false) {
this.innerShow = true
}
},
disPopUp() {
if (this.innerShow === true) {
this.innerShow = false
}
},
openPrivacyContract() {
wx.openPrivacyContract({
success: res => {
console.log('打开《用户隐私指引保护》内容成功')
},
fail: res => {
console.error('打开《用户隐私指引保护》内容失败', res)
}
})
}
}
}
</script>
<style lang="scss">
</style>
<template>
<view v-if="innerShow" @touchmove.stop.prevent class="flex alcenter justify-center"
style="position: fixed;left:0;top:0;z-index:999;width:100vw;height:100vh;background-color: rgba(0,0,0,0.5);"
:style="{top:(scrollTop||0) 'px'}">
<view class="pd40 bdr16 bg-w">
<view class="mb20 text-center">
<text class="ft20 text-main ftwbold">{{title}}</text>
</view>
<scroll-view class="ft16" :scroll-y="true" style="max-height: 50vh;width: 75vw;">
<text class="text-info" space="nbsp"> {{desc1}}</text>
<text class="text-red" @tap="openPrivacyContract">{{urlTitle}}</text>
<text class="text-info">{{desc2}}</text>
</scroll-view>
<view class="mt40 flex alcenter justify-between">
<button style="margin:0" size="mini" id="disagree-btn" type="default" @tap="handleDisagree">不同意</button>
<button style="margin:0" size="mini" id="agree-btn" type="warn" open-type="agreePrivacyAuthorization"
@agreeprivacyauthorization="handleAgree">同意并继续</button>
</view>
</view>
</view>
</template>
<!-- 注:text-info、text-main、text-red为CSS::color -->
<script>
let privacyHandler
let privacyResolves = new Set()
let closeOtherPagePopUpHooks = new Set()
if (wx.onNeedPrivacyAuthorization) {
wx.onNeedPrivacyAuthorization(resolve => {
console.log('触发《用户隐私指引保护》弹窗 onNeedPrivacyAuthorization')
if (typeof privacyHandler === 'function') {
privacyHandler(resolve)
}
})
}
const closeOtherPagePopUp = (closePopUp) => {
closeOtherPagePopUpHooks.forEach(hook => {
if (closePopUp !== hook) {
hook()
}
})
}
export default {
name: "privacy-popup",
props: {
scrollTop: {
type: Number,
default: 0
},
isSingleCheck: { // 是否单次检查隐私同意状态,因为同意隐私后,代码默认会执行(回调)该页面中Set集合存储的所有隐私接口操作。如果页面中有多个隐私接口回调,可能导致程序异常。
type: Boolean,
default: false
}
},
data() {
return {
title: "用户隐私保护提示",
desc1: " 感谢您使用本小程序,依据法规,在您使用本小程序前应当阅读并同意",
urlTitle: "《用户隐私保护指引》",
desc2: "当您点击同意并开始使用产品服务时,即表示你已理解并同意该条款内容,该条款将对您产生法律约束力。如您拒绝,应当停止使用本小程序。",
innerShow: false
}
},
mounted() {
this.ponLoad(true)
},
destroyed() {
if (this.closePopUp) {
console.error("隐私组件已关闭[destroyed]")
closeOtherPagePopUpHooks.delete(this.closePopUp)
this.closePopUp = null
}
},
methods: {
ponLoad(isChildMounted =
false
) { // 因为一些页面(父组件)在生命周期onLoad时就调用隐私接口了,比这个隐私子组件的生命周期mounted早执行,所以要优先初始化弹出方法(父组件以$ref形式调用)。换个说法,在执行当前组件mounted之前调用隐私接口了的页面,需要提前执行this.$ref.privacyPopup?.ponLoad()以支持弹窗打开。
if (!this.closePopUp) {
console.error(`隐私组件已加载[${isChildMounted?'子mounted':'onLoad'}]`)
const closePopUp = () => {
this.disPopUp()
}
privacyHandler = resolve => {
if (this.isSingleCheck) {
privacyResolves.clear()
}
privacyResolves.add(resolve)
this.popUp()
// 额外逻辑:当前页面的隐私弹窗弹起的时候,关掉其他页面的隐私弹窗
closeOtherPagePopUp(closePopUp)
}
this.closePopUp = closePopUp
closeOtherPagePopUpHooks.add(this.closePopUp)
}
},
ponUnload() { // 兼容tabBar页(onHide)与普通页(onUnload)跳转,使得再次访问页面时能够弹出弹出
if (this.closePopUp) {
console.error("隐私组件已关闭[onUnload]")
closeOtherPagePopUpHooks.delete(this.closePopUp)
this.closePopUp = null
}
},
ponHide() { // 兼容tabBar页(onHide)与tabBar页(onHide)跳转,使得再次访问页面时能够弹出弹出
if (this.closePopUp) {
console.error("隐私组件已关闭[onHide]")
closeOtherPagePopUpHooks.delete(this.closePopUp)
this.closePopUp = null
}
},
onDisagree() { // 点击不同意时,主动关闭
// if (this.closePopUp) {
// console.error("隐私组件已关闭[onDisagree]")
// closeOtherPagePopUpHooks.delete(this.closePopUp)
// this.closePopUp = null
// }
},
handleAgree(e) {
this.disPopUp()
// 这里演示了同时调用多个wx隐私接口时要如何处理:让隐私弹窗保持单例,点击一次同意按钮即可让所有pending中的wx隐私接口继续执行
privacyResolves.forEach(resolve => {
resolve({
event: 'agree',
buttonId: 'agree-btn'
})
})
privacyResolves.clear()
},
handleDisagree(e) {
this.disPopUp()
privacyResolves.forEach(resolve => {
resolve({
event: 'disagree',
})
})
privacyResolves.clear()
// this.onDisagree()
},
popUp() {
if (this.innerShow === false) {
this.innerShow = true
}
},
disPopUp() {
if (this.innerShow === true) {
this.innerShow = false
}
},
openPrivacyContract() {
wx.openPrivacyContract({
success: res => {
console.log('打开《用户隐私指引保护》内容成功')
},
fail: res => {
console.error('打开《用户隐私指引保护》内容失败', res)
}
})
}
}
}
</script>
<style lang="scss">
</style>
收起阅读 »

关于项目编辑发现的问题
这个问题源于我之前的一个帖子,感兴趣的可以去看看
(https://ask.dcloud.net.cn/question/175955)
简单来说就是HbuilderX不编译项目,起初我以为是我用的windows11的问题,直到今天我忍无可忍重装了win10系统,一遍遍尝试,才终于确定了问题
由于我本身是个PHP开发,同时也负责一部分前端开发工作;所以我习惯性在使用编辑器的时候,将所有项目的父级目录拖进编辑器(因为用的集成环境,所有项目都存放在一个目录中,这样后面不管是新建项目或者删除项目,都不需要在编辑器中做移除或新增操作);
由此就带出了这个HbuilderX不编译项目的问题,其实说白了就是目录层级过多,导致HbuilderX无法识别当前这个项目是否是uniapp项目,所以他会出现一个这样的提示(附件图片一)
既然知道了原因,解决办法也很简单,不要图省事,一个个把uniapp项目拖进HbuilderX再运行,就不会出现这样的问题了
仅此记录
2023.9.14
这个问题源于我之前的一个帖子,感兴趣的可以去看看
(https://ask.dcloud.net.cn/question/175955)
简单来说就是HbuilderX不编译项目,起初我以为是我用的windows11的问题,直到今天我忍无可忍重装了win10系统,一遍遍尝试,才终于确定了问题
由于我本身是个PHP开发,同时也负责一部分前端开发工作;所以我习惯性在使用编辑器的时候,将所有项目的父级目录拖进编辑器(因为用的集成环境,所有项目都存放在一个目录中,这样后面不管是新建项目或者删除项目,都不需要在编辑器中做移除或新增操作);
由此就带出了这个HbuilderX不编译项目的问题,其实说白了就是目录层级过多,导致HbuilderX无法识别当前这个项目是否是uniapp项目,所以他会出现一个这样的提示(附件图片一)
既然知道了原因,解决办法也很简单,不要图省事,一个个把uniapp项目拖进HbuilderX再运行,就不会出现这样的问题了
仅此记录
2023.9.14

引入uniapp项目写的H5页面 uni.postMessage 无法使用
在uniapp 项目中 引入使用uniapp开发打包部署成的H5页面
按照官方文档
引入https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js脚本
后会存在冲突,导致uni.postMessage 无法使用
本人踩坑后修改其源码解决了此冲突, 制作成npm 包,直接安装使用即可
安装: npm i y_uniwebview
引入: import y_uni from "y_uniwebview"
使用:y_uni.postMessage()
在uniapp 项目中 引入使用uniapp开发打包部署成的H5页面
按照官方文档
引入https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js脚本
后会存在冲突,导致uni.postMessage 无法使用
本人踩坑后修改其源码解决了此冲突, 制作成npm 包,直接安装使用即可
安装: npm i y_uniwebview
引入: import y_uni from "y_uniwebview"
使用:y_uni.postMessage()
收起阅读 »
uni可用的new URL(),直接获取url中的参数等信息
插件传送门 uni可用的new URL()
// 从自己所放到路径引入,检查路径和文件名是否正确,错误请自己修改
import URL from '@/js_sdk/cainiao-url/url.js'
const url = new URL('https://www.aaa.com:8989/bbb/ccc/ddd.html?e=1&f=2&g#h=3&i=4&j?k=5#l=6&e=4')
console.log(url)
{
"href": "https://www.aaa.com:8989/bbb/ccc/ddd.html?e=1&f=2&g#h=3&i=4&j?k=5#l=6&e=4",
"origin": "https://www.aaa.com",
"protocol": "https:",
"host": "www.aaa.com",
"port": "8989",
"pathname": "/bbb/ccc/ddd.html",
"search": "?e=1&f=2&g&k=5",
"hash": "#h=3&i=4&j&l=6&e=4",
"params": {
"h": "3",
"i": "4",
"l": "6",
"e": "1",
"f": "2",
"k": "5"
}
}
插件传送门 uni可用的new URL()
// 从自己所放到路径引入,检查路径和文件名是否正确,错误请自己修改
import URL from '@/js_sdk/cainiao-url/url.js'
const url = new URL('https://www.aaa.com:8989/bbb/ccc/ddd.html?e=1&f=2&g#h=3&i=4&j?k=5#l=6&e=4')
console.log(url)
{
"href": "https://www.aaa.com:8989/bbb/ccc/ddd.html?e=1&f=2&g#h=3&i=4&j?k=5#l=6&e=4",
"origin": "https://www.aaa.com",
"protocol": "https:",
"host": "www.aaa.com",
"port": "8989",
"pathname": "/bbb/ccc/ddd.html",
"search": "?e=1&f=2&g&k=5",
"hash": "#h=3&i=4&j&l=6&e=4",
"params": {
"h": "3",
"i": "4",
"l": "6",
"e": "1",
"f": "2",
"k": "5"
}
}
收起阅读 »

新版 3.8.7 插件下载 网络失败的问题
日志为
http request QUrl("http://update.liuyingyong.cn/hbuilderx/upgrade_repositories/3.8.7.20230703/win32/plugins/index.json?tmp=16312") : connect to server timeout
2023-09-13 10:36:16.084 [WARNING:] http request QUrl("http://update.liuyingyong.cn/hbuilderx/alpha/win32/update/index.json?tmp=38166091") : connect to server timeout
解决方案:开VPN下
日志为
http request QUrl("http://update.liuyingyong.cn/hbuilderx/upgrade_repositories/3.8.7.20230703/win32/plugins/index.json?tmp=16312") : connect to server timeout
2023-09-13 10:36:16.084 [WARNING:] http request QUrl("http://update.liuyingyong.cn/hbuilderx/alpha/win32/update/index.json?tmp=38166091") : connect to server timeout
解决方案:开VPN下

在 uniapp 中使用 unplugin-vue-components 编译成小程序代码后异常缺失 js 文件
我在 vite.config.ts 中配置了自动生成类型声明的组件后,代码可以实现类型提示高亮
但在小程序中会出现以下报错:[ app.json 文件内容错误] app.json: 未找到 ["pages"][0] 对应的 pages/index/index.js 文件(env: macOS,mp,1.06.2307260; lib: 3.0.2)
我寻找到 dist/dev/mp-weixin/pages/index/index 中发现编译后并没有生成 index.js 文件导致的
当我尝试注释掉 vite.config.js 中的配置后就是正常的,如下图
在此向询问一下有遇到过该问题的大佬是如何解决,或者是否有更好的办法来实现自动导入组件后 自动生成组件的类型声明,感谢!
我在 vite.config.ts 中配置了自动生成类型声明的组件后,代码可以实现类型提示高亮
但在小程序中会出现以下报错:[ app.json 文件内容错误] app.json: 未找到 ["pages"][0] 对应的 pages/index/index.js 文件(env: macOS,mp,1.06.2307260; lib: 3.0.2)
我寻找到 dist/dev/mp-weixin/pages/index/index 中发现编译后并没有生成 index.js 文件导致的
当我尝试注释掉 vite.config.js 中的配置后就是正常的,如下图
在此向询问一下有遇到过该问题的大佬是如何解决,或者是否有更好的办法来实现自动导入组件后 自动生成组件的类型声明,感谢!
收起阅读 »
来来来,给你们看看云端打包的速度
[HBuilder] 11:03:55.857 项目 xxxx的打包状态:
[HBuilder] 11:03:55.857 时间: 2023-09-12 10:41:20 类型: Android云端证书 正在云端打包
[HBuilder] 11:03:55.857 预计2-5分钟完成打包。如项目使用了App原生插件,打包时间可能会较长,请耐心等待。
[HBuilder] 11:04:53.821 项目 xxxx的打包状态:
[HBuilder] 11:04:53.821 时间: 2023-09-12 10:41:20 类型: Android云端证书 正在云端打包
[HBuilder] 11:04:53.821 预计2-5分钟完成打包。如项目使用了App原生插件,打包时间可能会较长,请耐心等待。
[HBuilder] 11:05:53.630 项目 xxxx的打包状态:
[HBuilder] 11:05:53.630 时间: 2023-09-12 10:41:20 类型: Android云端证书 正在云端打包
[HBuilder] 11:05:53.630 预计2-5分钟完成打包。如项目使用了App原生插件,打包时间可能会较长,请耐心等待。
这种速度真垃圾
首先声明,我这应用里面不包含原生插件,不包含第三方东西
这速度,吃屎估计都赶不上热乎的吧
[HBuilder] 11:03:55.857 项目 xxxx的打包状态:
[HBuilder] 11:03:55.857 时间: 2023-09-12 10:41:20 类型: Android云端证书 正在云端打包
[HBuilder] 11:03:55.857 预计2-5分钟完成打包。如项目使用了App原生插件,打包时间可能会较长,请耐心等待。
[HBuilder] 11:04:53.821 项目 xxxx的打包状态:
[HBuilder] 11:04:53.821 时间: 2023-09-12 10:41:20 类型: Android云端证书 正在云端打包
[HBuilder] 11:04:53.821 预计2-5分钟完成打包。如项目使用了App原生插件,打包时间可能会较长,请耐心等待。
[HBuilder] 11:05:53.630 项目 xxxx的打包状态:
[HBuilder] 11:05:53.630 时间: 2023-09-12 10:41:20 类型: Android云端证书 正在云端打包
[HBuilder] 11:05:53.630 预计2-5分钟完成打包。如项目使用了App原生插件,打包时间可能会较长,请耐心等待。
这种速度真垃圾
首先声明,我这应用里面不包含原生插件,不包含第三方东西
这速度,吃屎估计都赶不上热乎的吧

app启动图
1.安卓用android studio工具,就是不太好画,对图形内容有要求;
2.ios用Xcode做,Xcode下面有个预览,可以看看在各个手机的展示效果,就可以看到了。
1.安卓用android studio工具,就是不太好画,对图形内容有要求;
2.ios用Xcode做,Xcode下面有个预览,可以看看在各个手机的展示效果,就可以看到了。

小程序分包显示不出来的原因!—— 竟然如此简单?
长话短说,偶然发现uni-app文档中分包的内容与小程序的内容不一样
具体如下:
该图 为uni-app开发文档中的
注意:"subPackages" 中的P为大写
下面这张图为 微信小程序开发文档中的
注意:"subpackages" 中的p为小写
如果没仔细看文档的话 可能会找半天bug...
因为一个字母大小写的原因导致 分包没有显示出来!!!
长话短说,偶然发现uni-app文档中分包的内容与小程序的内容不一样
具体如下:
该图 为uni-app开发文档中的
注意:"subPackages" 中的P为大写
下面这张图为 微信小程序开发文档中的
注意:"subpackages" 中的p为小写
如果没仔细看文档的话 可能会找半天bug...
因为一个字母大小写的原因导致 分包没有显示出来!!!
收起阅读 »
【经验分享】HX 源代码格式化用法
作为一枚强迫症程序员,如果源代码格式不能精细控制,那是不可接受的。
HBuilderX 是一款功能强大的 IDE 工具,它提供了多种途径用于对源代码格式进行控制,但要完全驾驭它还需要一些经验。
我这里把个人摸索的结果做个小结,希望有人能觉得有用。
主要考虑的文件类型:
.js
.css
.vue
主要考虑的格式:
- 缩进用空格而不是
tab
- 缩进 2 个空格
HX 中编辑代码时,有几处设置可以控制格式风格,优先级从低到高:
- 主菜单【重排代码格式】,实际采用的是
%AppData%\Roaming\HBuilder X\extensions\format\jsbeautifyrc.js
- 主菜单【编辑-缩进】里面设置
- 项目中的
.jsbeautifyrc
配置文件 - 项目中的
.eslintrc.js
配置文件(需安装 eslint-js 和 eslint-plugin-vue 插件)
其中 1/2/3 是在 HX 里【重排代码格式】时起作用,4 是在保存文件时自动触发(如果开启了的话)。
考虑到格式风格的选择与项目相关,所以最好是在项目的根目录下放置 .jsbeautifyrc
和 .eslintrc.js
配置文件。
下面的配置文件可以解决大部分问题:
// .jsbeautifyrc
{
"js": {
"indent_size": 2,
"indent_char": " ",
"indent_with_tabs": false,
"jslint_happy": true
},
"css": {
"indent_size": 2,
"indent_char": " ",
"indent_with_tabs": false
}
}
// .eslintrc.js
module.exports = {
"extends": "plugin:vue/vue3-recommended",
"rules":{
'vue/html-indent': ['error', 2, {
baseIndent: 0
}],
'vue/first-attribute-linebreak': ['error', {
singleline: 'ignore',
multiline: 'below'
}],
'vue/max-attributes-per-line': ['error', {
singleline: 3,
multiline: 1
}],
'vue/script-indent': ['error', 2, {
baseIndent: 0
}],
'no-trailing-spaces': 'error',
'no-multi-spaces': 'error',
'no-mixed-spaces-and-tabs': ['error', 'smart-tabs'],
'no-tabs': 'error',
'indent': ['error', 2],
}
}
注意事项
在 HX 的编辑器中打开 .js
文件时,如果进行【重排代码格式】操作,是 jsbeautify
在起作用,而在保存时的自动重排,是 eslint-js
插件在起作用。
如果两者的格式设置冲突的话,后者会最终胜出,但操作过程会比较困惑。
所以应尽量设置成保持一致,且一般不用【重排代码格式】,不过有些混乱的代码可能需要先用【重排代码格式】来整理一下效果会更好。
作为一枚强迫症程序员,如果源代码格式不能精细控制,那是不可接受的。
HBuilderX 是一款功能强大的 IDE 工具,它提供了多种途径用于对源代码格式进行控制,但要完全驾驭它还需要一些经验。
我这里把个人摸索的结果做个小结,希望有人能觉得有用。
主要考虑的文件类型:
.js
.css
.vue
主要考虑的格式:
- 缩进用空格而不是
tab
- 缩进 2 个空格
HX 中编辑代码时,有几处设置可以控制格式风格,优先级从低到高:
- 主菜单【重排代码格式】,实际采用的是
%AppData%\Roaming\HBuilder X\extensions\format\jsbeautifyrc.js
- 主菜单【编辑-缩进】里面设置
- 项目中的
.jsbeautifyrc
配置文件 - 项目中的
.eslintrc.js
配置文件(需安装 eslint-js 和 eslint-plugin-vue 插件)
其中 1/2/3 是在 HX 里【重排代码格式】时起作用,4 是在保存文件时自动触发(如果开启了的话)。
考虑到格式风格的选择与项目相关,所以最好是在项目的根目录下放置 .jsbeautifyrc
和 .eslintrc.js
配置文件。
下面的配置文件可以解决大部分问题:
// .jsbeautifyrc
{
"js": {
"indent_size": 2,
"indent_char": " ",
"indent_with_tabs": false,
"jslint_happy": true
},
"css": {
"indent_size": 2,
"indent_char": " ",
"indent_with_tabs": false
}
}
// .eslintrc.js
module.exports = {
"extends": "plugin:vue/vue3-recommended",
"rules":{
'vue/html-indent': ['error', 2, {
baseIndent: 0
}],
'vue/first-attribute-linebreak': ['error', {
singleline: 'ignore',
multiline: 'below'
}],
'vue/max-attributes-per-line': ['error', {
singleline: 3,
multiline: 1
}],
'vue/script-indent': ['error', 2, {
baseIndent: 0
}],
'no-trailing-spaces': 'error',
'no-multi-spaces': 'error',
'no-mixed-spaces-and-tabs': ['error', 'smart-tabs'],
'no-tabs': 'error',
'indent': ['error', 2],
}
}
注意事项
在 HX 的编辑器中打开 .js
文件时,如果进行【重排代码格式】操作,是 jsbeautify
在起作用,而在保存时的自动重排,是 eslint-js
插件在起作用。
如果两者的格式设置冲突的话,后者会最终胜出,但操作过程会比较困惑。
所以应尽量设置成保持一致,且一般不用【重排代码格式】,不过有些混乱的代码可能需要先用【重排代码格式】来整理一下效果会更好。
收起阅读 »