- 用小程序原生框架开发时,你可能还需要一个状态管理工具
我希望只依照小程序的文档,用小程序原生框架进行开发而不用去引入其它前端框架从而增加复杂度。 而在用原生框架时,唯一缺失的就是一个类似Redux,Mobx这样的状态管理工具
2018-10-28 - 利用云函数解决域名校验和HTTPS相关问题
闲来无事,无意中发现云函数中的request网络请求可以不用配置校验域名和https,也就是说可以通过云函数封装一个请求通用函数来处理没有域名和https的网络请求(甚至包括内网穿透,可以用非80端口进行实验)。 适用场景: A、没有域名或使用局域网(直接使用IP访问); B、使用花生壳动态域名解析(内网穿透); C、有域名但不想申请配置HTTPS(懒人); D、连自己的服务器都没有,接口直接使用开源或者第三方接口且不能添加域名校验的情况(空壳); E、不愿意直接在小程序中直接暴露自己逻辑API实际请求地址的(安全); ······ 具体步骤如下: 1、给项目添加云函数支持(https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html) 2、新建名为“proxy”的云函数,配置支持request-promise [代码]// package.json[代码][代码]{[代码][代码] [代码][代码]"name"[代码][代码]: [代码][代码]"proxy"[代码][代码],[代码][代码] [代码][代码]"version"[代码][代码]: [代码][代码]"1.0.0"[代码][代码],[代码][代码] [代码][代码]"description"[代码][代码]: [代码][代码]""[代码][代码],[代码][代码] [代码][代码]"main"[代码][代码]: [代码][代码]"index.js"[代码][代码],[代码][代码] [代码][代码]"scripts"[代码][代码]: {[代码][代码] [代码][代码]"test"[代码][代码]: [代码][代码]"echo \"Error: no test specified\" && exit 1"[代码][代码] [代码][代码]},[代码][代码] [代码][代码]"author"[代码][代码]: [代码][代码]""[代码][代码],[代码][代码] [代码][代码]"license"[代码][代码]: [代码][代码]"ISC"[代码][代码],[代码][代码] [代码][代码]"dependencies"[代码][代码]: {[代码][代码] [代码][代码]"wx-server-sdk"[代码][代码]: [代码][代码]"latest"[代码][代码],[代码][代码] [代码][代码]"request"[代码][代码]: [代码][代码]"latest"[代码][代码],[代码][代码] [代码][代码]"request-promise"[代码][代码]: [代码][代码]"latest"[代码][代码] [代码][代码]}[代码][代码]}[代码][代码]// 云函数入口文件index.js[代码] [代码]const cloud = require([代码][代码]'wx-server-sdk'[代码][代码])[代码][代码]const rq = require([代码][代码]'request-promise'[代码][代码])[代码][代码]cloud.init()[代码][代码]// 云函数入口函数[代码][代码]// event为小程序调用的时候传递参数,包含请求参数uri、headers、body[代码][代码]exports.main = async (event, context) => {[代码][代码] [代码][代码]return[代码] [代码]await rq({[代码][代码] [代码][代码]method: [代码][代码]'POST'[代码][代码],[代码][代码] [代码][代码]uri: event.uri,[代码][代码] [代码][代码]headers: event.headers ? event.headers : {},[代码][代码] [代码][代码]body: event.body[代码][代码] [代码][代码]}).then(body => {[代码][代码] [代码][代码]return[代码] [代码]body[代码][代码] [代码][代码]}).[代码][代码]catch[代码][代码](err => {[代码][代码] [代码][代码]return[代码] [代码]err[代码][代码] [代码][代码]})[代码][代码]}[代码]3、在小程序中调用云函数请求数据请求 [代码]onLoad: [代码][代码]function[代码][代码](){[代码][代码] [代码][代码]// 初始化[代码][代码] [代码][代码]wx.cloud.init()[代码][代码]},[代码][代码]onGetItemList: [代码][代码]function[代码][代码](){[代码][代码] [代码][代码]wx.cloud.callFunction({[代码][代码] [代码][代码]name: [代码][代码]'proxy'[代码][代码],[代码][代码] [代码][代码]data: {[代码][代码] [代码][代码]// http域名 https域名 第三方域名 非验证域名 IP[:prot] 内网IP或花生壳域名[代码][代码] [代码][代码]uri: [代码][代码]'http://192.168.1.100:8081'[代码][代码],[代码][代码] [代码][代码]headers: {[代码][代码] [代码][代码]'Content-Type'[代码][代码]: [代码][代码]'application/json'[代码][代码] [代码][代码]},[代码][代码] [代码][代码]body: {[代码][代码] [代码][代码]uid: 1[代码][代码] [代码][代码]}[代码][代码] [代码][代码]}[代码][代码] [代码][代码]}).then(res => {[代码][代码] [代码][代码]console.log(res)[代码][代码] [代码][代码]const data = res.result[代码][代码] [代码][代码]console.log(data)[代码][代码] [代码][代码]// do something[代码][代码] [代码][代码]})[代码][代码]}[代码]然后你会发现你已经无所不能了。 个人见解,如有不妥之处,望各位大神指正!~
2018-12-03 - 叠式轮播图
开发工具和iOS测过,android我没测过。。哈哈哈哈哈 https://developers.weixin.qq.com/s/kh8HhjmA7A4D 注释不知道写啥,简单描述了下 [图片]
2018-11-30 - 将二进制数据的图片转化为base64
知识点 wx.request的参数对象responseType。文档地址 [图片] 示例[代码]wx.request({ [代码] [代码] url: `requseturl`, [代码] [代码] method: 'GET', [代码] [代码] responseType: 'arraybuffer', [代码] [代码] success: function (res) { [代码] [代码] if (res.statusCode === 200) { [代码] [代码] let base64 = wx.arrayBufferToBase64(res.data); [代码] [代码] console.log(base64);[代码] [代码] } } })[代码]
2018-11-27 - 想要获得unionid,最少得话900块,小程序要认证,开放平台得认证,公众号还
想要获得unionid,最少得话900块,小程序要认证,开放平台得认证,公众号还得认证! 微信开放平台绑定了, 又花了300块, 我是创业者, 每一块钱都要掰成几份花。 小程序认证300, 开放平台300, 还有一个企业服务号300。 同一个主体, 多次重复认证收费, 太他的欺负人了。 还每年得交。其实他们什么也没干。
2018-11-26 - 小程序有没有类似vue或者mobx提供的计算属性?
小程序有没有类似vue或者mobx提供的计算属性? 比如登录的这个业务场景: 需要输入账户,且账户位数是11位 需要输入验证码,且验证码位数是4位 此时,登录的按钮才可以点击。 目前小程序里面实现是这样的: [代码]Page({[代码][代码] [代码][代码]data: {[代码][代码] [代码][代码] phoneValue: [代码][代码]''[代码][代码],[代码][代码] [代码][代码] verifyCodeValue: [代码][代码]''[代码][代码],[代码][代码] [代码][代码] canLogin: [代码][代码]false[代码][代码],[代码][代码] [代码][代码]},[代码][代码] [代码][代码]bindPhoneInput: [代码][代码]function[代码] [代码](e) {[代码][代码] [代码][代码] const phoneValue = e.detail.value;[代码][代码] [代码][代码] [代码][代码]this[代码][代码].setData({ phoneValue, canLogin: [代码][代码]false[代码] [代码]});[代码][代码] [代码][代码] const { verifyCodeValue } = [代码][代码]this[代码][代码].data;[代码][代码] [代码][代码] [代码][代码]if[代码] [代码](phoneValue && verifyCodeValue && phoneValue.length == 11 && verifyCodeValue.length == 4) {[代码][代码] [代码][代码] [代码][代码]this[代码][代码].setData({ canLogin: [代码][代码]true[代码] [代码]});[代码][代码] [代码][代码] }[代码][代码] [代码][代码]},[代码][代码] [代码][代码]bindVerifyCodeInput: [代码][代码]function[代码] [代码](e) {[代码][代码] [代码][代码] const verifyCodeValue = e.detail.value;[代码][代码] [代码][代码] [代码][代码]this[代码][代码].setData({ verifyCodeValue, canLogin: [代码][代码]false[代码] [代码]})[代码][代码] [代码][代码] const { phoneValue } = [代码][代码]this[代码][代码].data;[代码][代码] [代码][代码] [代码][代码]if[代码] [代码](phoneValue && verifyCodeValue && phoneValue.length == 11 && verifyCodeValue.length == 4) {[代码][代码] [代码][代码] [代码][代码]this[代码][代码].setData({ canLogin: [代码][代码]true[代码] [代码]});[代码][代码] [代码][代码] }[代码][代码] [代码][代码]}[代码][代码]})[代码] 这样的代价是需要在需要组合属性判断的地方,全部都维护一次canLogin来渲染页面,组合属性越多的话,代码维护就越麻烦,且非常不优雅。 有没有类似vue里面的computed,或者是mobx里面的computed这种计算属性的方式来应对这种业务需求呢?
2018-01-31 - picker-view中indicator-style没作用
picker-view中indicator-style和indicator-class设置选择器中间选中框的样式,好像只有indicator-style的height起作用,要是设置选择器中间选中框的样式为没有边框和改变颜色该怎么设置[图片]
2017-12-11 - 云开发支付的代码,有需要的进。
真机测试已通过。你照抄就行,保证可通过。 最新完美版本可供参考: https://developers.weixin.qq.com/community/develop/article/doc/0004c4a50a03107eaa79f03cc56c13 小程序端: wx.cloud.callFunction({ name: 'getPay' , data: { total_fee: parseFloat(0.01).toFixed(2) * 100, attach: 'anything', body: 'whatever' } }) .then( res => { wx.requestPayment({ appId: res.result.appid, timeStamp: res.result.timeStamp, nonceStr: res.result.nonce_str, package: 'prepay_id=' + res.result.prepay_id, signType: 'MD5', paySign: res.result.paySign, success: res => { console.log(res) } }) }) 云函数:getPay getPay目录下共两个文件: 1、index.js 2、package.json index.js代码如下: const key = "YOURKEY1234YOURKEY1234YOURKEY123"//这是商户的key,不是小程序的密钥,32位。 const mch_id = "1413090000" //你的商户号 //将以上的两个参数换成你的,然后以下可以不用改一个字照抄 const rp = require('request-promise') const crypto = require('crypto') function paysign({ ...args }) { let sa = [] for (let k in args) sa.push( k + '=' + args[k]) sa.push( 'key=' + key) return crypto.createHash('md5').update(sa.join('&'), 'utf8').digest('hex').toUpperCase() } exports.main = async (event, context) => { const appid = event.userInfo.appId const openid = event.userInfo.openId const attach = event.attach const body = event.body const total_fee = event.total_fee const notify_url = "https://whatever.com/notify" const spbill_create_ip = "118.89.40.200" const nonce_str = Math.random().toString(36).substr(2, 15) const timeStamp = parseInt(Date.now() / 1000) + '' const out_trade_no = "otn" + nonce_str + timeStamp let formData = "<xml>" formData += "<appid>" + appid + "</appid>" formData += "<attach>" + attach + "</attach>" formData += "<body>" + body + "</body>" formData += "<mch_id>" + mch_id + "</mch_id>" formData += "<nonce_str>" + nonce_str + "</nonce_str>" formData += "<notify_url>" + notify_url + "</notify_url>" formData += "<openid>" + openid + "</openid>" formData += "<out_trade_no>" + out_trade_no + "</out_trade_no>" formData += "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>" formData += "<total_fee>" + total_fee + "</total_fee>" formData += "<trade_type>JSAPI</trade_type>" formData += "<sign>" + paysign({ appid, attach, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee, trade_type: 'JSAPI' }) + "</sign>" formData += "</xml>" let res = await rp({ url: "https://api.mch.weixin.qq.com/pay/unifiedorder", method: 'POST',body: formData}) let xml = res.toString("utf-8") if (xml.indexOf('prepay_id')<0) return xml let prepay_id = xml.split("<prepay_id>")[1].split("</prepay_id>")[0].split('[')[2].split(']')[0] let paySign = paysign({ appId: appid, nonceStr: nonce_str, package: ('prepay_id=' + prepay_id), signType: 'MD5', timeStamp: timeStamp }) return { appid, nonce_str, timeStamp, prepay_id, paySign } } package.json 代码如下: { "name": "getPay", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "youself", "license": "ISC", "dependencies": { "crypto": "^1.0.1", "request-promise": "^4.2.2" } } 最后选择:上传和部署:云端安装依赖。
2019-12-14 - 在小程序使用jsEncrypt.js
问题描述由于jsEncrypt.js代码里面含有window、document、navigator对象,这些对象可以在pc端的浏览器使用,但是小程序没有这些对象,所以直接在小程序引入jsEncrypt.js会直接报错,下面主要介绍如何在jsEncrypt.js里面对这些对象进行兼容。 jsEncrypt.js介绍功能一种RSA加密的解决方案。 这种加密模式被称为"非对称加密算法"。 (1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。 (2)甲方获取乙方的公钥,然后用它对信息加密。 (3)乙方得到加密后的信息,用私钥解密。 如果公钥加密的信息只有私钥解得开,那么只要私钥不泄漏,通信就是安全的。 使用场景加密验证码。 [代码]// 实例化JSEncrypt对象。并设置公钥[代码] [代码]var cryptFirst = new JSEncrypt();[代码] [代码]cryptFirst.setPublicKey('-----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALQCZoxawKSTyMTLEU5QlYNVIOBMafGq vVGp6bFv2gQ8Px5ZJVzIG1TjIUQo1IpGQBgC+JSJFaGLsv196dlcloUCAwEAAQ== -----END PUBLIC KEY-----');[代码][代码]// 实例化JSEncrypt对象。并设置私钥[代码] [代码]var cryptSec = new JSEncrypt();[代码] [代码]cryptSec.setPrivateKey('-----BEGIN PRIVATE KEY----- MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAtAJmjFrApJPIxMsR TlCVg1Ug4Exp8aq9UanpsW/aBDw/HlklXMgbVOMhRCjUikZAGAL4lIkVoYuy/X3p 2VyWhQIDAQABAkBwdoN9MwHikNZBZSGFzUDsEZZ9rCAQtXycdcykZ95NAA5Mlb0j 77FLUhON8XEa+YVORwYn2GoP+ZZxGib7OtYBAiEA4nJRIzFn2Yr6y36r1rI6GP28 lxEDe5z/wytqm+XFswUCIQDLgJis+LVfzLM0MLVzDyuEy2GoLY46+WnaW8J2PSet gQIhANykSLzC2g6VJbN8VJFYjdVl/wkvMbaTjn4r4q/OnejFAiBPatgqaMUfpdsp uviU9o6dPGHYKC8hhMRymuzBCAy8AQIhAJlTJgdsJD7cjDCvFOv5v2Xz1JQQp03I vGjIsmEbdbEp -----END PRIVATE KEY-----'); var text = 'secret';[代码][代码]// 使用公钥加密数据[代码] [代码]var enc = cryptFirst.encrypt(text);[代码] [代码]// 现在使用私钥解密数据[代码] [代码]var dec = cryptSec.decrypt(enc);[代码] [代码]console.log(dec === text); // true[代码]开始兼容处理源代码在线预览:源代码地址 兼容window.crypto源代码第2754行 [代码]if (window.crypto && window.crypto.getRandomValues) { // 生成长度为256,元素值为0的数组 var z = new Uint32Array(256); // 生成长度为256,元素随机值的数组 window.crypto.getRandomValues(z); }[代码]兼容代码 [代码]var getRandomValues = function (array) { [代码] [代码] for (var i = 0, l = array.length; i < l; i++) {[代码] [代码] array[i] = Math.floor(Math.random() * 256); } return array;[代码][代码]}[代码] [代码]var z = new Uint32Array(256);[代码] [代码]getRandomValues(z);[代码]兼容window.removeEventListener、window.detachEvent源代码 [代码]if (window.removeEventListener) { [代码] [代码] window.removeEventListener("mousemove", onMouseMoveListener_1, false);[代码] [代码]} else if ([代码]window.detachEvent) { window.detachEvent("onmousemove", onMouseMoveListener_1); [代码]}[代码]兼容处理: 直接删掉,监听的事件不会影响到加密和解密 兼容navigator.appName、navigator.userAgent源代码 [代码]if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) { BigInteger.prototype.am = am2; dbits = 30; } else if (j_lm && (navigator.appName != "Netscape")) { BigInteger.prototype.am = am1; dbits = 26; } else { // Mozilla/Netscape seems to prefer am3 BigInteger.prototype.am = am3; dbits = 28; }[代码]兼容处理: 直接删掉。navigator主要是对浏览器的判断 最后去一个在线压缩js的网站压缩一下代码,然后在小程序里引入就搞定啦。 总结兼容处理其实比较简单粗暴,主要学到了一些第三方库在小程序的兼容处理其实很简单,不用太过畏惧修改源码。
2018-11-21 - 如何隐藏滚动条?
如果想隐藏子组件的滚动条,需要在【父组件】的css样式中添加下面的样式,注意在子组件中添加是没有效果的。 [代码]::-webkit-scrollbar{ [代码] [代码] width: 0; [代码] [代码] height: 0; [代码] [代码] color: transparent; [代码] [代码] display: none;[代码] [代码]}[代码]
2018-11-19 - display和opacity的动画
问题描述在做小程序的弹窗的时候,需要实现一个透明度的渐变动画,并且在关闭的时候把弹窗移除。如果不移除的话,就无法选中弹窗层级下面的元素。 需要实现的效果[图片] 这个功能有两个要求: 透明度渐变的动画 点击关闭的时候把弹窗移除,让其不要再占据空间。 刚开始我是怎么写的hah[代码]/* 显示样式*/[代码] [代码].modal-visible { [代码] [代码] display: block; [代码] [代码] opacity: 1; [代码] [代码] transition: opacity 100ms ease;[代码] [代码]}[代码] [代码] [代码] [代码]/* 隐藏样式*/[代码] [代码].modal-hidden { [代码] [代码] display: none; [代码] [代码] opacity: 0; [代码] [代码] transition: opacity 100ms ease;[代码] [代码]}[代码]然后保存发现并没有透明度的过渡效果!!!! 解决过程上google搜索[代码]display animation stackoverflow[代码],发现有很多人跟我遇到了同样的问题。 链接 https://stackoverflow.com/questions/8449933/animation-css3-display-opacity/8450102 问题出现的原因元素先执行了display为none,再去执行opacity的渐变动画,由于元素被提前移除,导致后面的动画执行无效。 常用的解决方法1. 使用css3的animation [代码]@keyframes fadeInFromNone {[代码][代码] 0% { [代码] [代码] display: none; [代码] [代码] opacity: 0;[代码] [代码] }[代码][代码] 1% { [代码] [代码] display: block; [代码] [代码] opacity: 0;[代码] [代码] }[代码][代码] 100% { [代码] display: block; [代码] opacity: 1;[代码] [代码] } }[代码] 2. 使用css的visible、height、transition-delay实现[代码]visible[代码]可以隐藏元素,但是隐藏后元素并没有移除,所以需要让元素的高度变为0,让其不再占据空间。 利用transition-delay让元素height变为0延迟执行,在opacity的渐变动画执行完再去执行height变化 [代码].modal-visilble { [代码] [代码] visibility: visible; [代码] [代码] height: auto; [代码] [代码] opacity: 1; [代码] [代码] /* 100ms为动画执行时间, 0ms为延迟时间 */[代码] [代码] transition: opacity 100ms ease 0ms; [代码][代码]}[代码] [代码] [代码] [代码].modal-hidden { [代码] [代码] visibility: hidden; [代码] [代码] opacity: 0; [代码] [代码] height: 0; [代码] [代码] transition: height 0ms ease 100ms, visibility 100ms ease 0ms, opacity 100ms ease 0ms; [代码] [代码]}[代码]3. 结合使用js。在动画结束的时候让元素display为none 两种方法 第一种: 监听动画的transitionend事件 第二种: 定时器。设定[代码](setTimeout)[代码]为动画的执行时间,定时器时间到了之后移除元素(display: none)。 总结主要是对css动画属性更熟悉了 transition-delay、animation,以及动画结束的事件transitionend 欢迎点赞hahaha
2018-11-01 - web-view 怎么调用 jssdk 的接口
- 需求的场景描述(希望解决的问题) 在小程序web-view想调用jssdk中的上传图片功能,用的是小程序appid和secret获取的签名(小程序没有关联公众号),然后wx.config这在开发者工具里报错{"errMsg":"config:fail,Error: invalid url domain"},在手机里预览报config:invalid signature. 我想知道小程序web-view里的H5页面需要怎么配置才可以调用jssdk的上传图片接口? 或者在web-view里的H5页面用什么方式才能调用小程序的上传接口?
2018-06-15 - webview中chooseImage:fail无法唤起相册
在webview中 chooseImage:fail无法唤起相册 chooseImage:fail, the permission value is offline verifying
2018-09-07