微信小程序踩坑+客服功能实现

最近在开发一款微信小程序,其中也是踩了不少坑,部分的坑小东还是发出来瞅瞅吧,还有更多的坑还没来得及记录,都在脑子里,欢迎付费咨询,啊哈哈哈哈…

微信小程序开发,抢占市场先机

0x01 tabBar排序

tabBar 排序根据 app.json中的 pages 顺序


0x02 引号 & 花括号

花括号和引号之间如果有空格,将最终被解析成为字符串


0x03 wx:for循环key绑定

对象中,可以绑定unique-key值,数组使用 wx:key="*this",多层嵌套循环使用wx:for-item="i"来指定成员的别名;默认index变量为数组下标,使用wx:for-index="idx" 来指定下标别名


0x04 多个组件在if,for等渲染

如果要一次性判断多个组件标签,可以使用一个 <block/> 标签将多个组件包装起来,并在上边使用 wx:if控制属性。

wx:if与hidden的开销:一般来说,wx:if 有更高的切换消耗而 hidden有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。


0x05 列表组件中的图片头像高度占位问题

我在实现工作列表的过程中,点击文字区域,可以正常传值跳转,但是点击图片发现跳转的是下一行的内容,经过审查元素,发现图片是一个高度占位的,它的高度有240px,但是宽度只有60px,解决办法是:设置固定高度即可;


0x06 PHP substr()函数问题

substr()截取字符串的时候,会因为中英文混杂,导致中文字符缺失,json编码会返回false,所以不使用????查看文档,还有mb_substr()这个函数,第四个参数设置编码即可。


0x07 scrolltolower事件触发问题

scroll-view以及page的高度都设置为100%,可以解决scrolltolower事件触发不了的问题。另一种方式可以使用 onReachBottom()来监听触底操作。swiperscroll-view配合使用可以实现页面滑动,TAB切换的效果


0x08 编码问题

在小程序中,获取用户昵称,或者与用户的输入有交互的时候,最好是采用BASE64编码的方式,对用户的输入进行编码存储数据库,然后再解码输出,解决部分图标字符(emoji表情)等导致写数据库失败的问题


0x09 小程序的生命周期

下面的图引用自官方文档,个人理解是:onLoadonShowonReadyonHideonUnload,很容易理解的字面意思,如果在子页面有更细数据的操作,父级页面的数据需要刷新,那么可以使用onShow监听事件内写需要更新数据的一些操作函数,非常方便。

页面的生命周期


0x0a Json数据

一般json数据的大小最好控制在64Kb


0x0b 微信小程序客服参考

一个参考案例,小东对PHP熟悉,所以下面是个PHP的例子,方便给大家Copy,哈哈~,官方的参考文档并不是很全面,下面这个大家直接套用就好了。另外官方文档位置->【戳我

<?php
// AUTHOR: DYBOY
// EMAIL: dyboy2017@qq.com

define("TOKEN","blogdyboycn");//填写自己设置的Token

class wechatAPI{

    const APP_ID = 'APPID';                //填写微信小程序的APPID
    const APP_SECRET = 'APPSECRET';        //填写微信小程序的APPSECRET

    //用于小程序第一步验证返回
    public function isValid(){
        $echoStr = $_GET["echostr"];
        if ($this->checkSignature()) {
            echo $echoStr;
            exit;
        }
    }

    // 验证签名
    public function checkSignature(){
        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];
        $token = TOKEN;
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode( $tmpArr );
        $tmpStr = sha1( $tmpStr );
        if( $tmpStr == $signature ){
            return true;
        }else{
            return false;
        }
    }

    // 发送消息
    public function send($data){
        $url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=".$this->getAccessToken();
        $data = urldecode(json_encode($data));
        $this->curl_post($url,$data);
    }

    //xml数据转数组
    public function xml2Array($contents = NULL, $encoding = 'UTF-8', $get_attributes = 1, $priority = 'tag'){
        if (!$contents)
        {
            return array();
        }
        if (!function_exists('xml_parser_create'))
        {
            return array ();
        }
        $parser = xml_parser_create('');
        xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $encoding);
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
        xml_parse_into_struct($parser, trim($contents), $xml_values);
        xml_parser_free($parser);
        if (!$xml_values)
            return array();
        $xml_array = array ();
        $parents = array ();
        $opened_tags = array ();
        $arr = array ();
        $current = & $xml_array;
        $repeated_tag_index = array ();
        foreach ($xml_values as $data)
        {
            unset ($attributes, $value);
            extract($data);
            $result = array ();
            $attributes_data = array ();
            if (isset ($value))
            {
                if ($priority == 'tag')
                    $result = trim($value);
                else
                    $result['value'] = trim($value);
            }
            if (isset ($attributes) && $get_attributes) {
                foreach ($attributes as $attr => $val)
                {
                    if ($priority == 'tag')
                        $attributes_data[$attr] = $val;
                    else
                        $result['attr'][$attr] = $val; 
                }
            }
            if ($type == "open")
            {
                $parent[$level -1] = & $current;
                if (!is_array($current) || (!in_array($tag, array_keys($current)))) {
                    $current[$tag] = $result;
                    if ($attributes_data)
                        $current[$tag . '_attr'] = $attributes_data;
                    $repeated_tag_index[$tag . '_' . $level] = 1;
                    if (isset($tag) && $tag && isset($current[$tag])) {
                        $current = & $current[$tag];
                    }
                }
                else
                {
                    if (isset ($current[$tag][0]))
                    {
                        $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
                        $repeated_tag_index[$tag . '_' . $level]++;
                    }
                    else
                    { 
                        $current[$tag] = array (
                            $current[$tag],
                            $result
                        ); 
                        $repeated_tag_index[$tag . '_' . $level] = 2;
                        if (isset ($current[$tag . '_attr']))
                        {
                            $current[$tag]['0_attr'] = $current[$tag . '_attr'];
                            unset ($current[$tag . '_attr']);
                        }
                    }
                    $last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
                    $current = & $current[$tag][$last_item_index];
                }
            }
            elseif ($type == "complete")
            {
                if (!isset ($current[$tag]))
                {
                    $current[$tag] = $result;
                    $repeated_tag_index[$tag . '_' . $level] = 1;
                    if ($priority == 'tag' && $attributes_data) {
                        $current[$tag . '_attr'] = $attributes_data;
                    }
                }
                else
                {
                    if (isset ($current[$tag][0]) && is_array($current[$tag])) {
                        $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
                        if ($priority == 'tag' && $get_attributes && $attributes_data) {
                            $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
                        }
                        $repeated_tag_index[$tag . '_' . $level]++;
                    }
                    else
                    {
                        $current[$tag] = array (
                            $current[$tag],
                            $result
                        );
                        $repeated_tag_index[$tag . '_' . $level] = 1;
                        if ($priority == 'tag' && $get_attributes) {
                            if (isset ($current[$tag . '_attr']) && is_array($current[$tag]))
                            {
                                $current[$tag]['0_attr'] = $current[$tag . '_attr'];
                                unset ($current[$tag . '_attr']);
                            }
                            if ($attributes_data)
                            {
                                $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
                            }
                        }
                        $repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
                    }
                }
            }
            elseif ($type == 'close')
            {
                $current = & $parent[$level -1];
            }
        }
        return ($xml_array);
    }

    //获取accesstoken
    public function getAccessToken() {
        $tokenFile = "access_token.txt";
        $data = json_decode(file_get_contents($tokenFile,FILE_USE_INCLUDE_PATH));
        //accesstoken有效期是7200秒,这里用到的文件缓存
        //注意:文件权限问题
        if (!$data->expire_time || $data->expire_time < time()) {

            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".self::APP_ID."&secret=".self::APP_SECRET;

            $res =  json_decode(file_get_contents($url));
            if($res) {
                $arr = array();
                $access_token = $res->access_token;
                $arr['expire_time'] = time() + 7000;
                $arr['access_token'] = $access_token;
                $fp = fopen($tokenFile, "w");
                fwrite($fp, json_encode($arr));
                fclose($fp);
            }
        } else {
            $access_token = $data->access_token;
        }

        return $access_token;
    }

    //post发送json数据
    public function curl_post($url,$post_data){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        $res = curl_exec($ch);

        if(!$res){
            throw new Exception('发送消息失败:'.curl_error($ch));
        }
        curl_close($ch);
    }


};


$wechatObj = new wechatAPI();

//注意:第一步验证时打开,验证完成之后就可以注释了
// $wechatObj->isValid();

if($wechatObj->checkSignature() === true){

    $xmlstring = @file_get_contents("php://input");
    $accept_info = $wechatObj->xml2Array($xmlstring)['xml'];

    if($accept_info){
        $ToUserName = $accept_info['ToUserName'];
        $FromUserName = $accept_info['FromUserName'];
        $CreateTime = $accept_info['CreateTime'];
        $MsgType = $accept_info['MsgType'];
        $data = array();
        if($MsgType == 'text'){//接收文本
            $Content = $accept_info['Content'];//文本内容
            if($Content === '介绍') {
                $data['touser'] = $FromUserName;
                $data['msgtype'] = 'link';
                $data['link']['title'] = urlencode('DYBOY');
                $data['link']['description'] = urlencode('DYBOY是一个菜鸡博主!');
                $data['link']['url'] = 'https://blog.dyboy.cn';
                $data['link']['thumb_url'] = 'https://upload-images.jianshu.io/upload_images/6661013-1840bfc8f6f07536.jpg';
                $wechatObj->send($data);
                exit;
            }
            //else if 可以做好多事

        }else if($MsgType === 'image') {//接收图片
            $data['touser'] = $FromUserName;
            $data['msgtype'] = 'text';
            $data['text']['content'] = urlencode('~*^_^*~');//urlencode 解决中文乱码问题
            $wechatObj->send($data);
            exit;

        }else if($MsgType === 'event') {//进入客服窗口事件
            $Event = $accept_info['Event'];
            $SessionFrom = $accept_info['SessionFrom'];
            if($Event == 'user_enter_tempsession') {
                $data['touser'] = $FromUserName;
                $data['msgtype'] = 'text';
                $data['text']['content'] = urlencode('您好很高兴为您服务');//urlencode 解决中文乱码问题
                $wechatObj->send($data);
                exit;
            }
        }

        echo '<xml><ToUserName><![CDATA['.$FromUserName.']]></ToUserName><FromUserName><![CDATA['.$ToUserName.']]></FromUserName><CreateTime>'.$CreateTime.'</CreateTime><MsgType><![CDATA[transfer_customer_service]]></MsgType></xml>';
    }

}

0x0C 总结

最后总结一下,基本就是上面这样子了,还有的小东没想起来,如果有微信小程序及后台管理开发的可直接联系,价格从500到30000之间,价格可接受的可以直接联系。另外,写了一个小程序,不过没上线,也把码子发出来瞅瞅吧,万一哪天上线了呐???

重大实习生

发表评论 / Comment

用心评论~

金玉良言 / Appraise
LV 1
2019-05-01 19:12
学习了
头像
DYBOY站长已认证
2019-05-08 00:02
@狼:一起学习进步!
思源LV 2
2019-04-22 09:56
很赞
淘宝刷单平台LV 1
2019-04-16 16:49
技术神啊
头像
DYBOY站长已认证
2019-05-08 00:02
@淘宝刷单平台:哈哈,目前还是小菜一枚

Warning: Cannot modify header information - headers already sent by (output started at /www/wwwroot/blog.dyboy.cn/content/templates/dyblog/footer.php:56) in /www/wwwroot/blog.dyboy.cn/include/lib/view.php on line 23