HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

【经验分享】如何在多个云函数/云对象中共享本地公共模块代码(for Windows)

经验分享 技术分享

在 HX 开发的云服务项目中,可能存在多个云函数/云对象用到相同的代码模块。

如果这些模块来自于公共仓库的开源代码,那很简单,但如果是自己写的代码,在项目开发过程中随时还要修改,
那可能就需要在多个云函数/云对象中复制粘贴了,不仅繁琐,而且很可能出错。

解决的办法就是创建一个单独的目录用来存放这种本地公共代码模块,把公共代码模块放置在这个目录中,
然后在它们原本应该出现的地方用mklink 创建 JUNCTION 指向这里,那么只要在一处发生修改,
其它处也会随着变动,从而避免了手工维护的代码复制。

比如下面这种典型的目录结构:

<project root>  
├── uniCloud-aliyun  
│ ├── cloudfunctions  
│ │ ├── co-1  
│ │ │ ├── utils [JUNCTION]  
│ │ │ │ └── ...  
│ │ │ └── index.obj.js  
│ │ └── co-2  
│ │   ├── utils [JUNCTION]  
│ │   │ └── ...  
│ │   └── index.obj.js  
│ ...  
│   
└── local-shared  
    └── utils [JUNCTION TARGET]  
      └── ...

在上述目录结构下,创建两个 JUNCTION 的方法是在 co-1co-2 目录下分别执行下面的命令:

mklink /J utils ..\..\..\local-shared\utils

需注意的是,在把源代码提交到 git 仓库的时候,local-shared 目录下的 utils 目录不需要提交,
而要把每个云函数/云对象目录下的 JUNCTION 形式的 utils 目录都提交到 git,就像它们是那里的真实目录一样。

这样虽然在源代码仓库里面有重复的内容,但好处是别人在 checkout 代码之后会得到一个完整的项目目录,
而不用再去手工创建 JUNCTION。

当然如果他们也需要对项目做进一步开发,他们可以自己用同样的方法,把这些重复的目录搬到 local-shared
目录下,再手工创建 JUNCTION。

另外还有一点需要注意,如果 utils 模块依赖于另外一个本地模块,比如 const other = require('../other-util')
那么这个 other-util 模块也需要放置在 local-shared 目录下,并创建 JUNCTION,否则在 HX 里面
【运行-本地云对象】时会报错,因为它用相对路径加载被依赖模块时是以当前文件的真实位置开始算的。
不过,既然 utils 本身是一个公共模块,那它依赖的模块本来也就应该是一个公共模块,所以一起搬到 local-shared
目录下本来也是顺理成章的事了。

继续阅读 »

在 HX 开发的云服务项目中,可能存在多个云函数/云对象用到相同的代码模块。

如果这些模块来自于公共仓库的开源代码,那很简单,但如果是自己写的代码,在项目开发过程中随时还要修改,
那可能就需要在多个云函数/云对象中复制粘贴了,不仅繁琐,而且很可能出错。

解决的办法就是创建一个单独的目录用来存放这种本地公共代码模块,把公共代码模块放置在这个目录中,
然后在它们原本应该出现的地方用mklink 创建 JUNCTION 指向这里,那么只要在一处发生修改,
其它处也会随着变动,从而避免了手工维护的代码复制。

比如下面这种典型的目录结构:

<project root>  
├── uniCloud-aliyun  
│ ├── cloudfunctions  
│ │ ├── co-1  
│ │ │ ├── utils [JUNCTION]  
│ │ │ │ └── ...  
│ │ │ └── index.obj.js  
│ │ └── co-2  
│ │   ├── utils [JUNCTION]  
│ │   │ └── ...  
│ │   └── index.obj.js  
│ ...  
│   
└── local-shared  
    └── utils [JUNCTION TARGET]  
      └── ...

在上述目录结构下,创建两个 JUNCTION 的方法是在 co-1co-2 目录下分别执行下面的命令:

mklink /J utils ..\..\..\local-shared\utils

需注意的是,在把源代码提交到 git 仓库的时候,local-shared 目录下的 utils 目录不需要提交,
而要把每个云函数/云对象目录下的 JUNCTION 形式的 utils 目录都提交到 git,就像它们是那里的真实目录一样。

这样虽然在源代码仓库里面有重复的内容,但好处是别人在 checkout 代码之后会得到一个完整的项目目录,
而不用再去手工创建 JUNCTION。

当然如果他们也需要对项目做进一步开发,他们可以自己用同样的方法,把这些重复的目录搬到 local-shared
目录下,再手工创建 JUNCTION。

另外还有一点需要注意,如果 utils 模块依赖于另外一个本地模块,比如 const other = require('../other-util')
那么这个 other-util 模块也需要放置在 local-shared 目录下,并创建 JUNCTION,否则在 HX 里面
【运行-本地云对象】时会报错,因为它用相对路径加载被依赖模块时是以当前文件的真实位置开始算的。
不过,既然 utils 本身是一个公共模块,那它依赖的模块本来也就应该是一个公共模块,所以一起搬到 local-shared
目录下本来也是顺理成章的事了。

收起阅读 »

【B-ui】uni-app生态专用的移动端UI框架

ui库 ui组件 UI

B-ui

介绍

一款非组件化设计的uni-app生态专用的移动端UI框架,一款适合广大开发者轻易上手且能在新老项目中无负担使用的框架。

示例体验

平台 链接 二维码
H5 预览链接 <img width="200" src="https://mydarling.gitee.io/b-ui/_/h5.png">

框架文档

<font color="red">文档还在编写中,请先下载示例项目后参考示例项目使用</font>

框架下载&安装

下载:

  1. 前往 uni-app 下载市场:https://ext.dcloud.net.cn/plugin?id=10582
  2. 选择 使用 HBuilderX 导入插件 或 下载插件ZIP
  3. 如果是选择 HBuilderX 导入插件 则会自动安装,如果是选择 下载插件ZIP 把解压后的文件移入到 根目录/uni_modules/b-ui 目录中

安装:

  1. 安装CSS: App.vue 文件中添加如下代码
<style lang="scss">  
    /*每个页面公共css */  
    @import "@/uni_modules/b-ui/css/main.bundle.scss";  
</style>
  1. 安装JS: main.js 文件中添加如下代码
// 在 main.js 的最后面添加如下文件  
require("@/uni_modules/b-ui/js/main.bundle.js");

兼容说明

Vue版本兼容

Vue2 Vue3
未测试

平台兼容

H5 APP-Vue 微信小程序 APP-NVue 其他小程序 快应用 PC
× 理论兼容 懒得测试 不推荐使用

依赖说明

  • scss/sass,使用 HBuilder X 通过 菜单 “工具” > “插件安装” > “scss/sass编译” 进行安装

B-ui 名字的由来

  • 【Best 合适的】,这款UI是一个适合广大开发者轻易上手的。
  • 【Basic 基础的】,这款UI只提供基础的CSS布局和常用的轻型组件封装,对新老项目都能无负担的使用。
  • 【Beautiful 美丽的】,这款UI是美丽且符合大众审美的。

关于作者

  • 河浪
  • helang.love@qq.com
继续阅读 »

B-ui

介绍

一款非组件化设计的uni-app生态专用的移动端UI框架,一款适合广大开发者轻易上手且能在新老项目中无负担使用的框架。

示例体验

平台 链接 二维码
H5 预览链接 <img width="200" src="https://mydarling.gitee.io/b-ui/_/h5.png">

框架文档

<font color="red">文档还在编写中,请先下载示例项目后参考示例项目使用</font>

框架下载&安装

下载:

  1. 前往 uni-app 下载市场:https://ext.dcloud.net.cn/plugin?id=10582
  2. 选择 使用 HBuilderX 导入插件 或 下载插件ZIP
  3. 如果是选择 HBuilderX 导入插件 则会自动安装,如果是选择 下载插件ZIP 把解压后的文件移入到 根目录/uni_modules/b-ui 目录中

安装:

  1. 安装CSS: App.vue 文件中添加如下代码
<style lang="scss">  
    /*每个页面公共css */  
    @import "@/uni_modules/b-ui/css/main.bundle.scss";  
</style>
  1. 安装JS: main.js 文件中添加如下代码
// 在 main.js 的最后面添加如下文件  
require("@/uni_modules/b-ui/js/main.bundle.js");

兼容说明

Vue版本兼容

Vue2 Vue3
未测试

平台兼容

H5 APP-Vue 微信小程序 APP-NVue 其他小程序 快应用 PC
× 理论兼容 懒得测试 不推荐使用

依赖说明

  • scss/sass,使用 HBuilder X 通过 菜单 “工具” > “插件安装” > “scss/sass编译” 进行安装

B-ui 名字的由来

  • 【Best 合适的】,这款UI是一个适合广大开发者轻易上手的。
  • 【Basic 基础的】,这款UI只提供基础的CSS布局和常用的轻型组件封装,对新老项目都能无负担的使用。
  • 【Beautiful 美丽的】,这款UI是美丽且符合大众审美的。

关于作者

  • 河浪
  • helang.love@qq.com
收起阅读 »

2023年09月14日微信隐私协议政策再次调整【重大利好了属于是】

隐私 uniapp 微信小程序 隐私协议 隐私弹窗

背景

2023 年 09 月 14 日,微信团队再次更新了关于微信小程序隐私保护指引设置的公告:

2023.09.14更新:  

1. 隐私相关功能启用时间延期至 2023年10月17日。在 2023年10月17日之前,在 app.json 中配置 __usePrivacyCheck__: true 后,会启用隐私相关功能,如果不配置或者配置为 false 则不会启用。在 2023年10月17日之后,不论 app.json 中是否有配置 __usePrivacyCheck__,隐私相关功能都会启用。  

2. 新增官方隐私授权弹窗功能,相关功能参考下方官方隐私弹窗功能说明。此功能目前仍在开发阶段,开发者目前可以先阅读本指南文档和接口文档进行理解,平台将会尽快正式上线相关能力,上线后会在本指南文档中进行说明。

文中提到了,推迟隐私相关功能的启用时间到2023年10月17日,并且提供了兜底的组件,即使开发者不做隐私协议弹出框也无需担心小程序的使用问题。不过隐私保护指引还是要完善的。这对一些没有来得及开发相关功能的开发者来讲是重大利好,可以免去开发隐私弹框的麻烦了。以下是相关的链接

微信官方文档及公告地址

关于小程序隐私保护指引设置的公告

隐私相关接口

微信小程序隐私协议开发指南

更新用户隐私保护指引

小程序管理员或开发者可以根据具体小程序涉及到的隐私相关接口来更新微信小程序后台的用户隐私保护指引,更新并审核通过后就可以进行相关的开发调试工作。

如果还是想要自己定制弹出框的样式的话还是可以使用组件来实现的。

这里就推荐一下我提供的组件 ws-wx-privacy 微信隐私保护弹出框,支持vue2和vue3

上一篇文章

uni-app 微信小程序隐私协议开发实践

Vue3高颜值组件库

Wot Design Uni | 一个参照Wot-design打造的uni-app组件库

继续阅读 »

背景

2023 年 09 月 14 日,微信团队再次更新了关于微信小程序隐私保护指引设置的公告:

2023.09.14更新:  

1. 隐私相关功能启用时间延期至 2023年10月17日。在 2023年10月17日之前,在 app.json 中配置 __usePrivacyCheck__: true 后,会启用隐私相关功能,如果不配置或者配置为 false 则不会启用。在 2023年10月17日之后,不论 app.json 中是否有配置 __usePrivacyCheck__,隐私相关功能都会启用。  

2. 新增官方隐私授权弹窗功能,相关功能参考下方官方隐私弹窗功能说明。此功能目前仍在开发阶段,开发者目前可以先阅读本指南文档和接口文档进行理解,平台将会尽快正式上线相关能力,上线后会在本指南文档中进行说明。

文中提到了,推迟隐私相关功能的启用时间到2023年10月17日,并且提供了兜底的组件,即使开发者不做隐私协议弹出框也无需担心小程序的使用问题。不过隐私保护指引还是要完善的。这对一些没有来得及开发相关功能的开发者来讲是重大利好,可以免去开发隐私弹框的麻烦了。以下是相关的链接

微信官方文档及公告地址

关于小程序隐私保护指引设置的公告

隐私相关接口

微信小程序隐私协议开发指南

更新用户隐私保护指引

小程序管理员或开发者可以根据具体小程序涉及到的隐私相关接口来更新微信小程序后台的用户隐私保护指引,更新并审核通过后就可以进行相关的开发调试工作。

如果还是想要自己定制弹出框的样式的话还是可以使用组件来实现的。

这里就推荐一下我提供的组件 ws-wx-privacy 微信隐私保护弹出框,支持vue2和vue3

上一篇文章

uni-app 微信小程序隐私协议开发实践

Vue3高颜值组件库

Wot Design Uni | 一个参照Wot-design打造的uni-app组件库

收起阅读 »

苹果xs 使用 open-type="chooseAvatar" 报错

微信小程序 uniapp

[Component] <button>: chooseAvatar:fail errcode:-207 cronet_error_code:-207 error_msg:net::ERR_CERT_INVALID

第一次获取可以获取到微信头像,然后关闭小程序再打开就报这个错,而且从相册选择图片也无法选择

继续阅读 »

[Component] <button>: chooseAvatar:fail errcode:-207 cronet_error_code:-207 error_msg:net::ERR_CERT_INVALID

第一次获取可以获取到微信头像,然后关闭小程序再打开就报这个错,而且从相册选择图片也无法选择

收起阅读 »

微信隐私弹框解决方案

隐私弹窗 隐私政策 微信小程序

根据微信官网最新关于用户隐私做出的更改,特此推出该插件,仅限于微信小程序使用,注意做好跨平台判断<!-- #ifdef MP-WEIXIN -->组件<!-- #endif -->,

需要注意:
1、微信公众平台登录->设置->服务内容声明->用户隐私保护指引 更新并声明项目用到的隐私相关接口的用途(很关键,不然不会触发隐私弹框),
2、manifest.json是否加入"usePrivacyCheck": true
3、组件是否正确导入、注册并使用
4、小程序基础库是否大于2.32.3

具体使用流程请看组件微信用户隐私弹框组件,不用自己判断是否同意的回调,组件会在用户调用隐私相关接口时自行弹框,组均封装完成,开箱即用,同时弹框有唯一性,多个弹框弹出回开启一个并自动关闭其他弹框

如使用过程中有问题或有一些好的建议,欢迎加QQ群互相学习交流:120594820

继续阅读 »

根据微信官网最新关于用户隐私做出的更改,特此推出该插件,仅限于微信小程序使用,注意做好跨平台判断<!-- #ifdef MP-WEIXIN -->组件<!-- #endif -->,

需要注意:
1、微信公众平台登录->设置->服务内容声明->用户隐私保护指引 更新并声明项目用到的隐私相关接口的用途(很关键,不然不会触发隐私弹框),
2、manifest.json是否加入"usePrivacyCheck": true
3、组件是否正确导入、注册并使用
4、小程序基础库是否大于2.32.3

具体使用流程请看组件微信用户隐私弹框组件,不用自己判断是否同意的回调,组件会在用户调用隐私相关接口时自行弹框,组均封装完成,开箱即用,同时弹框有唯一性,多个弹框弹出回开启一个并自动关闭其他弹框

如使用过程中有问题或有一些好的建议,欢迎加QQ群互相学习交流:120594820

收起阅读 »

mui索引列表indexed-list不能滑动

mui

刚开始是把索引列表dom放在了区域滚动组件的里面,到时索引列表滑动卡顿;
找半天原因没找到,然后把索引列表从区域滚动don里面拿出来就可以正常滑动了;
...(* ̄0 ̄)ノ

刚开始是把索引列表dom放在了区域滚动组件的里面,到时索引列表滑动卡顿;
找半天原因没找到,然后把索引列表从区域滚动don里面拿出来就可以正常滑动了;
...(* ̄0 ̄)ノ

【上架公告】APP上架、微信小程序上架陆陆续续需要备案(不是网站备案,比如APP需要APP备案,其他同理)

上架被拒 上架

=====注意不是网站备案,快应用不清楚,不过icp备案有可以查询快应用备案=====
https://baijiahao.baidu.com/s?id=1775739033371418952&wfr=spider&for=pc

=====华为应用市场已经有检测了=====

=====小米、vivo、oppo应用市场的通知=====

=====icp备案网站=====

↓↓↓ 各位大佬点点赞

继续阅读 »

=====注意不是网站备案,快应用不清楚,不过icp备案有可以查询快应用备案=====
https://baijiahao.baidu.com/s?id=1775739033371418952&wfr=spider&for=pc

=====华为应用市场已经有检测了=====

=====小米、vivo、oppo应用市场的通知=====

=====icp备案网站=====

↓↓↓ 各位大佬点点赞

收起阅读 »

一个关于微信小程序《用户隐私保护指引》的自定义组件

经验分享
<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 无法使用

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()

收起阅读 »