最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 公众号开发踩坑记录

    正文概述 掘金(不爱bug爱掘金)   2021-02-07   633

    真机调试公众号网页

    1. 修改本机 hosts 文件

    打开 hosts 文件,Windows 上在 C:\Windows\System32\drivers\etc 文件夹下,将我们公众号内配置的域名指向 127.0.0.1 ,如下图:

    公众号开发踩坑记录

    修改完毕之后保存,这时候跑起项目来,我们就可以在微信开发工具中通过访问 test.com + port 来访问我们的项目了。接下来通过 nodejs 写几行代码,使我们可以直接在80端口上访问项目

    2. 端口代理

    建立一个 js 文件,在我们启动项目的时候运行一下这个 js 文件,项目跑起来后,我们访问 test.com 就能直接访问到我们开发的项目了

    const http = require('http')
    const httpProxy = require('http-proxy')
    const proxy = httpProxy.createProxyServer()
    
    http.createServer(function(req, res) {
        // 8080 换成自己项目启动的端口
        proxy.web(req, res, { target: 'http://127.0.0.1:8080' })
    }).listen(80)
    

    3. 手机代理设置

    首先在电脑上安装Charles, Charles 是一个抓包工具,我们需要利用它来代理我们的手机网络请求,将我们手机的 test.com 的网络请求转发到本地。安装完毕后选择 代理 > 代理设置 设置代理端口,默认为8888,一般不需要更改。

    公众号开发踩坑记录

    然后手机操作,确保手机和电脑在同一个 WIFI 下,配置代理,服务器填写我们电脑在局域网内的 ip,可以通过 ipconfig 命令查询,端口填写PC上Charles刚刚设置的端口,配置完毕后我们在手机端输入 test.com 就可以愉快的在手机 debug 我们的前端项目了。

    公众号开发踩坑记录 公众号开发踩坑记录

    微信 js-sdk 的配置问题

    公众号开发大部分情况下都要用到微信提供的 js-sdk, 借助 js-sdk 可以使我们方便的调用手机的拍照、语音、位置、等手机系统功能以及一些微信特有的功能,这里我用到了 sdk 的拍照功能。在使用这个 sdk 前,需要先进行配置,执行 wx.config(options) 方法,配置成功后才可以进行调用。配置方法官网描述如下:

    公众号开发踩坑记录

    其中参数 signature 的生成步骤需要公众号的 AppSecret ,因此这一步要交给后端来完成,前端需要把URL传递给后端,后端获取到签名后返回给前端。在这里有几个坑需要说明一下:

    • 坑1:官网描述:同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用。 由于在微信中 url 可能在某些条件下微信会加一些参数形如 #STATE ,因此路由尽量使用 history 模式,因此通过URL获取签名的时候URL获取方式为:location.href.split('#')[0]。测试之后发现在安卓机和开发者工具上都正常,在 iOS 上提示 invalid signature ,但是刷新一下就提示:config: ok 了,肯定不能让用户去刷新的,一番搜索后发现在 iOS 上不管页面跳转几次都只认首次进入的URL,看到网上有些解决方案是缓存首次进入页面的URL,签名时使用缓存的URL,尝试了一下,都OK了,在iOS上尝试刷新一下结果又不行了,这次连 invalid signature 都没跳出来,wx.config 执行了后完全没反应,但是再刷新一次又可以了。折腾了半天后也没弄好,后来想了一下,既然 iOS 只认首次进入的URL,那么直接在首次进入页面的时候 config 一下不就好了,尝试了一下,做一个判断,如果是 iOS 就只在最顶层组件执行 config,尝试之后完美解决,首页配置后,其他页面调用sdk都没问题,不管刷新多少次都能弹出 config: ok
    • 坑2:拿到URL后需要使用 encodeURI 编码一下,否则某些情况还是会出现 invalid signature 的错误,比如URL中含有拼接的json字符串参数。
    • 坑3:在PC上的微信内置浏览器中配置成功的,提示:config: ok 但是在调用 sdk 具体功能时提示: permission denied 。这个暂时没找到解决方案,不过我这里只用到了选择图片之类的一些基本功能,在PC上都很好实现,就做了一个判断,如果是PC微信浏览器就不使用微信的 sdk,直接前端实现。

    js-sdk 选择多张图片问题

    微信的 sdk 调用都是回调函数的方式,为了方便使用时对其进行了 promise 化封装,调用了 chooseImage 方法和 getLocalImgData 方法,直接返回图片的 base64 数据,最开始 chooseImage 封装方法如下:

    // 有问题的版本
    const chooseImage = params => {
        return new Promise((resolve, reject) => {
            wx.chooseImage({
                ...params,
                success: res => {
                    const { localIds } = res
                    const results = localIds.map(localId => new Promise((innerResolve, innerReject) => {
                        wx.getLocalImgData({
                            localId,
                            success: response => innerResolve(response.localData),
                            fail: err => innerReject(err)
                        })
                    }))
                    return resolve(Promise.all(results))
                }
            })
        })
    }
    

    上面的方法在选择单张图片的时候没出现问题,但是在选择多张图片的时候发现只返回了一张图片,于是面向搜索引擎编程的我在各种搜索后发现 getLocalImgData 这个方法不能直接遍历,如果遍历执行他就只执行一次后面就不执行了,于是改为递归调用的方式,改进如下:

    // 可以正常选择多张的版本
    const chooseImg = params => {
        return new Promise((resolve, reject) => {
            wx.chooseImage({
                ...params,
                success: res => {
                    const { localIds } = res
                    const imgList = [] // 用来存储图片base64
                    const getResults = ids => {
                        const localId = localIds.shift()
                        wx.getLocalImgData({
                            localId,
                            success: response => {
                                const { localData } = response
                                imgList.push(localData)
                                if (ids.length > 0) {
                                    getResults(ids)
                                } else {
                                    // 递归结束
                                    return resolve(imgList)
                                }
                            }
                        })
                    }
                    getResults(localIds)
                },
                fail: error => {
                    return reject(error)
                },
            })
        })
    }
    

    移动端输入框 maxLength 遇到 emoji 的问题

    在移动端使用 input 输入框或者 textarea 文本域的时候,当限制了 maxLength 的时候,在安卓上和 iOS 上表现不同,不同的 emoji 表情的 length 有 2、3、4 等不同的值,但是在 iOS 上 emoji 的长度却被算做了1,比如限制了 maxLength 为5,在安卓上输入两个表情后就无法输入了,而在 iOS 上却可以输入5个 emoji,这个时候在输入框下面添加字数展示的时候,value.length 显示的可能是10或者更大的值,已经超出了我们限制的 maxLength, 因此这里要做一下统一处理,使用 js 来限制字数而不能用 maxLength 来限制,这里搜索了一下,网上大部分用到的方法都是监听输入,处理emoji,然后使用 value.slice(0, maxLength) 来处理的,这里有一个弊端,就是当用户输入已经达到最大限制的时候,把光标移到输入的文本中间,继续输入,会在光标处插入新输入的内容,尾部原来的内容就被截没了,而限制了 maxLength 的输入框在这种情况下是不能输入任何内容的,也不会修改原来的内容,这显然与预期不符合,因此不能简单的使用 slice 截取。

    这里先说一下含有 emoji 的字符串截取问题:上面说到 emoji 的length并不是1,因此当使用字符串的 slice 方法是就有可能遇到一个 emoji 表情被截一半的情况,这种情况下就会出现 这种方块问号的乱码,比如:

    const emojiStr = '123?'
    console.log(emojiStr.length) // 5
    emojiStr.slice(3, 4) // '�'
    

    使用 string.split('') 方法将含有 emoji 的字符串转为数组的时候,emoji 表情都会被截成一个个的,不过使用 Array.from(string) 方法可以将字符中的 emoji 保留而不被截断,如下:

    const emojiStr = '123?'
    emojiStr.split('') // ["1", "2", "3", "�", "�"]
    Array.from(emojiStr) // ["1", "2", "3", "?"]
    

    因此可以借助该方法处理含有 emoji 的字符串截取,方法如下:

    const sliceEmoji = (str, start, end) => {
      if (typeof str !== 'string' || start < 0 || end < 0 || start > end) {
        throw '参数非法'
      }
      const strArr = Array.from(s).slice(start, end)
      const slicedStr = s.slice(start, end)
      // 取两个字符串前面相同的一部分
      let result = ''
      if (strArr.join('') === slicedStr) {
        result = slicedStr
        return result
      }
      for (let i = 0; i < strArr.length; i++) {
        if (strArr[i] !== slicedStr[i]) {
          result = strArr.slice(0, i).join('')
          break
        }
      }
      return result
    }
    

    有了上面的认识,我们就可以按照以下方式来处理限制 maxLength 的输入框:

    const Textarea = () => {
        const [selection, setSelection] = useState({ start: 0, end: 0 }) // 用来记录光标位置
        const [value, setValue] = useState('') // 输入框值
        const textareaRef = useRef(null)
        const MAX_LENGTH = 20, // 这是根据需要设置的最大可输入值
        
        const onSelect = e => {
            const { selectionStart: start, selectionEnd: end } = e
            const el = textareaRef.current
            setSelection({ start, end })
        }
        
        const onChange = e => {
            const { start, end } = selection
            const val = e.target.value
            const length = value.length
            if (length <= MAX_LENGTH) {
                // 输入内容未达到限制长度
                setValue(val)
            } else {
                // 输入内容超出限制
                const delta = length - val.length // 输入内容与现有内容的差值
                const before = val.slice(0, start) // 光标之前的内容
                const after = val.slice(end + delta) // 光标之后的内容
                const diff = val.slice(start, delta) // 新输入的内容
                const validVal = sliceEmoji(diff, 0, MAX_LENGTH - value.length) // 可输入的内容
                const finallyVal = before + validVal + after // 输入框内最终的内容
    		    setValue(finallyVal)
            }
        }
        
        return <textarea ref={textareaRef} value={value} onSelect={onSelect} onChange={onChange} />
    }
    

    起源地下载网 » 公众号开发踩坑记录

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元