个人案例
码易呀嘿
一款可自定义内容,颜色,图片的二维码生成器
码易呀嘿扫码体验
全民乐抽
一款可抽奖的小程序
全民乐抽扫码体验
猿叔头像助手
一款可更换头像的小程序
猿叔头像助手扫码体验
- H5 跳转微信公众号链接 报错
Refused to frame 'https://mp.weixin.qq.com/' because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'self'
2022-02-21 - 07.Taro框架获取用户手机号解决方案
流程图 [图片] 核心代码 PhoneAuth 组件 [代码]import Taro from '@tarojs/taro'; import React, { useCallback, useEffect, useState } from 'react'; import { View, Button } from '@tarojs/components'; import { PLATFORM_TYPE } from '@/constant/index'; import tools from '@/utils/tools'; import './index.less'; // 工具方法 const PhoneManager: TaroMiniApp.IUtilsPhoneManager = { // 老版本: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/deprecatedGetPhoneNumber.html async oldVersionGetPhoneNumber(evt: TaroMiniApp.TGetPhoneNumberEvtDetail): Promise<TaroMiniApp.TaroApiResult> { return Taro.login() .then((codeRes: Taro.login.SuccessCallbackResult) => { // console.log(codeRes, evt); return this.getPhoneNumber(evt, codeRes.code) }) }, // 新版本: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html async newVersionGetPhoneNumber(evt: TaroMiniApp.TGetPhoneNumberEvtDetail): Promise<any> { console.log(evt); return this.getPhoneNumber(evt); }, // 获取支付宝绑定的手机号 async handleGetAliPayPhoneNumber(): Promise<TaroMiniApp.TaroApiResult> { try { const res = await (Taro as any).getPhoneNumber(); const data = JSON.parse(res.response); if (data.response.code !== 0) { return Promise.reject({ code: data.response.code, errMsg: 'getPhoneNumber:fail', data: { error: data.response }, }) } // TODO: 支付宝 return this.getPhoneNumber(data); } catch (error) { return Promise.reject({ code: 10, errMsg: 'getPhoneNumber:fail', data: { error: error }, }) } }, // TODO: 对接后端服务 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html getPhoneNumber(evtDetail: TaroMiniApp.TGetPhoneNumberEvtDetail, code?: string): Promise<TaroMiniApp.TaroApiResult> { // console.log(evtDetail, code); return Promise.resolve({ code: 0, errMsg: evtDetail?.detail?.errMsg, data: { phone: `121212-${code}` }, }) }, // 处理获取手机号事件 async handleGetPhoneNumberEvt(evt?: TaroMiniApp.TGetPhoneNumberEvtDetail): Promise<TaroMiniApp.TGetPhoneNumberResult> { if (PLATFORM_TYPE === 'WEAPP') { if (evt?.detail?.errMsg.indexOf('deny') !== -1) { return Promise.reject({ errMsg: evt?.detail.errMsg, code: 10, }) } // 获取系统信息 const { SDKVersion } = tools.getSystemInfo(); // console.log(SDKVersion, tools.compareVersion(SDKVersion, '2.21.2')); // 版本号对比 if (tools.compareVersion(SDKVersion, '2.21.2') === -1) { return this.oldVersionGetPhoneNumber(evt); } // new version return this.newVersionGetPhoneNumber(evt); } if (PLATFORM_TYPE === 'ALIPAY') { return this.handleGetAliPayPhoneNumber(); } const res = { code: 10, errMsg: 'getPhoneNumber: noSupport', data: {}, }; return Promise.resolve(res); }, } const PhoneAuth = (props: TaroMiniApp.IComponentsPhoneAuthProps) => { const [phoneNumberAuth, setPhoneNumber] = useState(false); useEffect(() => { if (PLATFORM_TYPE === 'ALIPAY') { Taro.getSetting() .then((res: Taro.getSetting.SuccessCallbackResult) => { setPhoneNumber((res.authSetting as any).phoneNumber); }); } }, []); const handleGetPhoneNumber = useCallback(async (evt) => { if (PLATFORM_TYPE === 'WEAPP') { PhoneManager.handleGetPhoneNumberEvt(evt).then((res) => { props.onSuccess(res) }).catch((err) => { props.onFail(err) }) return; } if (PLATFORM_TYPE === 'ALIPAY') { PhoneManager.handleGetPhoneNumberEvt().then((res) => { props.onSuccess(res) }).catch((err) => { props.onFail(err) }) } }, []); const getManualPhoneNumber = useCallback(async () => { PhoneManager.handleGetPhoneNumberEvt().then((res) => { props.onSuccess(res) }).catch((err) => { props.onFail(err) }) }, []); const onAuthError = useCallback((err) => { props.onFail({ code: 11, errMsg: 'getPhoneNumber: deny', data: err.detail }) }, []); const btnTxt = props.children || props.btnText || '手机号登录'; if (PLATFORM_TYPE !== 'ALIPAY' && PLATFORM_TYPE !== 'WEAPP') { return <View>不支持</View> } return ( <View className="phoneAuthContainer"> { PLATFORM_TYPE === 'WEAPP' && ( <Button style={`${props.btnStyle}`} className={`${props.uesSlot ? 'resetBtn' : ''}`} openType="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber} >{btnTxt}</Button> ) } {/* 支付宝已授权用户 */} { PLATFORM_TYPE === 'ALIPAY' && !phoneNumberAuth && ( <Button style={`${props.btnStyle}`} className={`${props.uesSlot ? 'resetBtn' : ''}`} openType="getAuthorize" scope='phoneNumber' onGetAuthorize={handleGetPhoneNumber} onError={onAuthError} >{btnTxt}</Button> ) } {/* 支付宝未授权用户 */} { PLATFORM_TYPE === 'ALIPAY' && phoneNumberAuth && ( <Button style={`${props.btnStyle}`} className={`${props.uesSlot ? 'resetBtn' : ''}`} onClick={getManualPhoneNumber} >{btnTxt}</Button> ) } </View> ); } export default PhoneAuth; [代码] 如何使用 [代码]import React, { useCallback } from 'react'; import { View, } from '@tarojs/components'; // 引入的 PhoneAuth 组件 import { PhoneAuth } from '@/components/index'; import './index.less'; export default function PhoneAuthDemo() { const handleSuccess = useCallback((res) => { console.log('success:', res); }, []); const handleFail = useCallback((err) => { console.log('fail:', err); }, []); const resetBtnStyle = "display: flex; background: #eee"; return ( <View className="page"> <View className='wrap'> <PhoneAuth onSuccess={handleSuccess} onFail={handleFail} /> </View> <View className='wrap'> <PhoneAuth onSuccess={handleSuccess} onFail={handleFail} btnText="自定义文本" /> </View> <View className='wrap'> <PhoneAuth onSuccess={handleSuccess} onFail={handleFail} btnStyle={resetBtnStyle} uesSlot> <View>我是自定义 slot</View> </PhoneAuth> </View> </View> ) } [代码]
2022-03-03 - 微信支付成功页下方展示小程序,请问如何设置?
[图片]
2022-02-23 - 目前为止项目中用到的一些校验
// 判断是否是json字符串 isJSON(str) { if (typeof str == 'string') { try { var obj=JSON.parse(str); if(typeof obj == 'object' && obj ){ return true; }else{ return false; } } catch(e) { return false; } } }, //验证手机号 checkPhone(phone){ var res = /^1[3456789]\d{9}$/; return res.test(phone);//返回true:手机号正确 false:手机号错误 }, // 国内座机 checkTel(phone){ var res = /\d{3}-\d{8}|\d{4}-\d{7}/; return res.test(phone);//返回true:正确 false:错误 }, // 验证邮箱(支持中文邮箱) checkEmail(email) { var res =/^[A-Za-z0-9\u4e00-\u9fa5]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,5}$/; return res.test(email);//返回true:邮箱正确 false:邮箱错误 }, // 验证中国大陆身份证号 checkIdcard(idcard) { var res = /(^\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$)|(^\d{6}(18|19|20)\d{2}(0\d|10|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)$)/; return res.test(idcard);//返回true:正确 false:错误 }, // 验证中国大陆一代身份证号 checkIdcard1(idcard){ var res =/^\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$/; return res.test(idcard);//返回true:正确 false:错误 }, // 验证中国大陆二代身份证号 checkIdcard2(idcard){ var res = /^\d{6}(18|19|20)\d{2}(0\d|10|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)$/; return res.test(idcard);//返回true:身份证正确 false:身份证错误 }, // 验证统一社会信用代码和组织机构代码 CheckSocialCreditCode(code){ var res = /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/; return res.test(code);//返回true:正确 false:错误 }, // 验证是否是图片链接 isImageUrl(str){ var res=/^https?:\/\/.*?(?:gif|png|jpg|jpeg|webp|svg|psd|bmp|tif)$/i; return res.test(str);//返回true:正确 false:错误 }, // 验证是否是视频链接 isVideoUrl(str){ var res=/^https?:\/\/.*?(?:swf|avi|flv|mpg|rm|mov|wav|asf|3gp|mkv|rmvb|mp4)$/i; return res.test(str);//返回true:正确 false:错误 }, // 是否是base64 isBase64(str){ var res=/^\s*data:(?:[a-z]+\/[a-z0-9-+.]+(?:;[a-z-]+=[a-z0-9-]+)?)?(?:;base64)?,([a-z0-9!$&',()*+;=\-._~:@/?%\s]*?)\s*$/i; return res.test(str);//返回true:正确 false:错误 }, // 验证银行卡号 isBankCard(str){ var res=/^[1-9]\d{9,29}$/; return res.test(str);//返回true:正确 false:错误 }, // 中文姓名 isChineseName(str){ var res=/^(?:[\u4e00-\u9fa5·]{2,16})$/; return res.test(str);//返回true:正确 false:错误 }, // 英文姓名 isEnglishName(str){ var res=/(^[a-zA-Z]{1}[a-zA-Z\s]{0,20}[a-zA-Z]{1}$)/; return res.test(str);//返回true:正确 false:错误 }, // 是否是新能源车牌号 isNewCarCard(str){ var res=/[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}(([0-9]{5}[DF])|([DF][A-HJ-NP-Z0-9][0-9]{4}))$/; return res.test(str);//返回true:正确 false:错误 }, // 非新能源车牌号 isOldCarCard(str){ var res=/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/; return res.test(str);//返回true:正确 false:错误 }, // 车牌号(新能源+非新能源) isCarCard(str){ var res=/^(?:[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}(?:(?:[0-9]{5}[DF])|(?:[DF](?:[A-HJ-NP-Z0-9])[0-9]{4})))|(?:[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9 挂学警港澳]{1})$/; return res.test(str);//返回true:正确 false:错误 }, // 护照 (包含香港、澳门) checkPassport(str){ var res=/(^[EeKkGgDdSsPpHh]\d{8}$)|(^(([Ee][a-fA-F])|([DdSsPp][Ee])|([Kk][Jj])|([Mm][Aa])|(1[45]))\d{7}$)/; return res.test(str);//返回true:正确 false:错误 }, // 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线组合) checkAccount(str){ var res=/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/; return res.test(str);//返回true:正确 false:错误 }, // 纯中文汉字 checkChineseWords(str){ var res=/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/; return res.test(str);//返回true:正确 false:错误 }, // 纯英文字母 checkEnglistWords(str){ var res=/^[a-zA-Z]+$/; return res.test(str);//返回true:正确 false:错误 }, // 是否是小数 isDecimal(str){ var res=/^\d+\.\d+$/; return res.test(str);//返回true:正确 false:错误 }, // 纯数字 isNumber(str){ var res=/^\d{1,}$/; return res.test(str);//返回true:正确 false:错误 }, // qq号 isQQNumber(str){ var res=/^[1-9][0-9]{4,10}$/; return res.test(str);//返回true:正确 false:错误 }, // 微信号 6至20位,以字母开头,字母,数字,减号,下划线 checkWxCode(str){ var res=/^[a-zA-Z][-_a-zA-Z0-9]{5,19}$/; return res.test(str);//返回true:正确 false:错误 }, // 中国邮政编码 checkChinaPostalCode(str){ var res=/^(0[1-7]|1[0-356]|2[0-7]|3[0-6]|4[0-7]|5[1-7]|6[1-7]|7[0-5]|8[013-6])\d{4}$/; return res.test(str);//返回true:正确 false:错误 }, // 判断字符串中是否含有表情 isEmojiCharacter(substring) { // if(isEmojiCharacter(str)){console.log('不能含有表情')} for (var i = 0; i < substring.length; i++) { var hs = substring.charCodeAt(i); if (0xd800 <= hs && hs <= 0xdbff) { if (substring.length > 1) { var ls = substring.charCodeAt(i + 1); var uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000; if (0x1d000 <= uc && uc <= 0x1f77f) { return true; } } } else if (substring.length > 1) { var ls = substring.charCodeAt(i + 1); if (ls == 0x20e3) { return true; } } else { if (0x2100 <= hs && hs <= 0x27ff) { return true; } else if (0x2B05 <= hs && hs <= 0x2b07) { return true; } else if (0x2934 <= hs && hs <= 0x2935) { return true; } else if (0x3297 <= hs && hs <= 0x3299) { return true; } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) { return true; } } } }, // 判断字符串中是否含有特殊字符 isTeShuString(substring){ var reg = /[~#^$@%&!?%*]/gi; return reg.test(substring); }, 不足之处忘大家指正,非常感谢
2022-02-22 - 迁移公证?
我迁移资料,需要公证!但是我之前注册的公众号的单位已经在两年前注销了!请问如何盖公章和迁移到新的公众号上
2022-02-21 - 如何在小程序中接入微信默认表情?
微信默认表情是否允许接入,有没有版权相关的问题? 想在小程序中接入微信默认表情,请问这个有没有接入方式? 谢谢~ [图片]
2022-02-21 - 如何搭建用户成长体系?
前言 在之前的文章中我提到了关于做用户留存的签到模块,其实签到模块只是用户成长体系积分中的获取途径之一,今天我和大家聊聊用户成长体系。你可以理解上之前那篇是技术篇主要讲解的是怎么做,这篇是产品篇主要讲解为什么要这样做。 相信你在生活中见过太多的用户成长体系,比如QQ会员、音乐会员、视频会员等等。那么为什么要有用户成长体系呢? 用户成长体系 用户成长体系本质上是用户精细化运营的重要手段。它可以提高用户忠诚度、提升用户留存、促进用户活跃。用户成长体系对于用户来说更是身份的象征,通过显著的会员等级标记,以及不经意之间的露出炫耀,让用户有更多的尊贵感,满足用户的虚荣心。 让用户去完成一些任务,获取积分的过程中,顺便提升等级。这样把用户进行了筛选,从而达到针对不同用户做出不同的产品策略。那么如何搭建用户成长体系呢? 第一步:分析数据 可以通过常用的用户分层模型 RFM 来进行区分。 [图片] RFM模型是衡量客户价值和客户创造利益能力的重要工具和手段。通过一个客户的近期购买行为、购买的总体频率以及花了多少钱3项指标来描述该客户的价值状况。 最近一次消费 (Recency) 消费频率 (Frequency) 消费金额 (Monetary) 通过以上模型,分析出来以下 4 类用户需要重点关注: 重要价值客户:最近消费时间近、消费频次和消费金额都很高,必须VIP服务。 重要保持客户:最近消费时间较远,但消费频次和金额都很高,需主动和他保持联系。 重要发展客户:最近消费时间较近、消费金额高,但频次不高,忠诚度不高,很有潜力的用户,必须重点发展。 重要挽留客户:最近消费时间较远、消费频次不高,但消费金额高的用户,可能是将要流失或者已经要流失的用户,应当给予挽留措施。 第二步:制定规则 用户体系通常的形态包含:积分、成长值、登记、勋章等,这个可以根据自己的产品来选择需要的形态。在这些形态中就需要一套合理的规则,制定规则的时候需要注意以下两点: 等级要循序渐进 在计算各等级成长值区间时,要像我们玩游戏打怪一样,越到后面越难,不同登记需要不同的成长速度,千万不要平均分配。 以QQ等级为例: [图片] 要遵循先易后难,这样才有挑战,我们可以把等级大概分成三个阶段。 初级,先让用户尝到甜头,降低门槛留存用户。 中级,筛选用户到这个级别有一定难度,能到达都是核心用户。 高级,能到这个登记的,那是最高价值的用户群体,需要重点对待。 有付出就要有回报 当用户完成某些任务获取到了积分,那么久需要有个场景能让积分进行消费可以是各种奖品、权益、勋章、功能等。明确告诉用户“你做什么能得到什么”。 在这里需要注意的就是需要提前去思考成本与收益。用户将积分兑换为权益所产生的成本应当小于该用户贡献的价值,这样才能保证不亏本。 第三步:目标导向 我们肯定是为了达成某个目标采取做的成长体系,所以不要盲目的去跟风做成长体系。在做之前想清楚自己的用户指标是什么,不要为了做而做,没有意义,浪费没必要的成本。 比如你想拉新,任务规则是:你在邀请朋友后,可以获得积分,这样做的目的是为了提高“新增”;也可以让你在连续签到 3 天获得双倍积分,这种方式就是通过提升“留存”的方式提升整个产品的用户指标。 小结 本篇文章主要讲解了: 为什么要做用户成长体系?本质是为了做用户的精细化运营 怎么做成长体系? 分析数据:不同用户不同对待方式 制定规则:先以后难,付出要有回报 目标导向:根据用户指标制定任务类型
2022-02-09 - 微信的unionid会变么?
如果公司的公众号迁移,会不会出现微信unionid变化的情况?
2022-01-10 - 现在能从我的小程序直接跳到别人的小程序里吗?有开发文档吗?
因为需要,想在我的小程序里,能打开别人的小程序,小程序目前能实现吗?有没有开发文档?
2022-01-10 - 这种小程序个人主体可以开发吗?
[图片] 这种弹框收款码怎么实现的? [图片]
2022-01-10 - 微信小程序5个不常见,但很实用的配置。
一、微信小程序资料页客服按钮配置。 1、配置前: [图片] 2、配置后: [图片] 3、配置方法: [图片] [图片] 注意要点: ·有客户通过这个按钮咨询,客服微信会收到服务通知。但要切换成在线状态才能收到。 ·因咨询有时效性,尽量让客户加客服微信再继续深度沟通。 [图片] 二、微信小程序允许被搜索开关。 这个功能跟另一个“暂停服务设置”有点像,但搜索开关和暂停服务还是有很大区别。比如一些内部的管理小程序,内部会经常用到。但不希望被非相关人员搜索到。又或者要注销的小程序,也可以关闭搜索再注销。不然注销完成了,还是有搜索信息展示。 配置方法: 小程序后台 > 设置 > 功能设置 > 私隐设置 [图片] 三、微信小程序资料页关联小程序。 1、配置前: [图片] 2、配置后: [图片] 3、配置路径: 小程序后台 > 设置 > 功能设置 > 相关小程序 [图片] 四、微信小程序资料页关联公众号。 1、配置前: [图片] 2、配置后: [图片] 3、配置路径: 小程序后台 > 设置 > 功能设置 > 相关公众号 [图片] 五、微信小程序支付后关注公众号。 本来这一条应该放在第一位,但可惜去年因影响用户体验,2021年8月19日功能下线。 [图片] 为什么还把这条不能配置放进来呢?不是为了凑数,而是想提醒社区的每一位开发或运营不要滥用微信生态功能!自己就亲身经历了很多士多连锁,支付后就收到公众号推送的一大堆广告。 除了这5个微信小程序配置,还想知道哪个配置(非代码)?可以评论区回复。
2022-01-06 - 小程序介绍页如何配置相关公众号、小程序?(如图)
小程序介绍页如何配置相关公众号、小程序?(如图) [图片][图片] 如上图,更多资料 下面是没内容的;怎么配置下图红框的功能? [图片]
2022-01-04