小程序架構

不知道大家們寫小程序是怎麼個寫法的,前幾個月在寫微信小程序,自己整理的一種架構,或者叫框架 微信原生的架構是這樣子 ├── app.js ├── app.json ├── app.wxss ├── pages │ │── index │ │ ├── index.wxml │ │ ├── index.js │ │ ├── index.json │ │ └── index.wxss │ └── logs │ ├── logs.wxml │ └── logs.js └── utils 為什麼不用微信原生的寫法呢? 小程序就類似手機APP,都會有一個tabBar欄對吧,微信官方的tabBar欄是在app.json中進行的全局配置。做一般的開發是沒有任何問題的,但涉及到一個複雜的tabBar欄時,使用官方原生的就無法實現,也無法動態載入,比如某影片app中間的拍照錄影功能 這意味著,我們不能使用官方給我們提供的tabBar欄,需要我們自己寫 最開始我的做法還是保持原生的結構,只是自己寫tabBar欄,所以頁面程式碼都寫在一個文件中,預設顯示第一屏,其他的都隱藏起來,切換頁面的時候再把相應的頁面顯示,其他的隱藏起來,並且動態渲染資料上去。但是有個問題是,如果是小專案倒沒什麼大問題,但是如果是大專案程式碼量非常龐大,都寫在一個文件中,後期難以維護,所以這個方法最後被pass掉 再後來將切換頁面的方式改為跳轉(wx.switchTab等),把不同頁面的程式碼放到了不同的文件,但是還有一個問題,切換也會閃爍,每次切換頁面就等於重新打開一個網頁一樣,tabBar都被重新渲染,所以會閃爍。pass 由此就有了現在的全新架構方式: 將/pages/index/下的文件全部定義為入口文件,js入口,css入口,視圖入口,不同頁面的文件還是放到不同的位置去,為了好管理,新建了一個template的資料夾,用於放不同頁面間的程式碼,結構和官方的單頁面結構是一樣的 根目錄下的app.js用於存放全域函數,其他頁面呼叫只需getApp()即可 js的入口文件 const app = getApp(); var index\_js = require("../../template/index/index.js"); var types\_js = require("../../template/types/types.js"); var Global\_Data = \[\]; Page({ data: { active: 0, show: { index: true, types: false, course: false, user: false } }, onLoad(options) { this.setData({ Global\_Data: index\_js.getData() }) }, // 底部nav切换 tabbar\_onChange(event) { var key = ''; this.data.show = { index: false, types: false, course: false, user: false }; console.log(event) switch (event.detail) { case 0: key = 'index'; Global\_Data = index\_js.getData(); break; case 1: key = 'types'; Global\_Data = types\_js.getData() break; case 2: key = 'course'; Global\_Data = index\_js.getData(); break; case 3: key = 'user'; Global\_Data = index\_js.getData(); break; } this.data.show\[key\] = true; console.log(Global\_Data) this.setData({ show: this.data.show, Global\_Data: Global\_Data }) }, }); wxml入口文件 ...

2019年5月17日 · 2 min · MoeJue

微信授權登入

文件:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319 微信的授權登入與QQ、新浪等平台的授權登入大同小異,均採用OauthOAuth2.0鑑權方式。 微信授權分為兩種: 靜默授權 彈窗授權,需要用戶手動同意 兩種scope的區別說明 以snsapi_base為scope發起的網頁授權,是用來獲取進入頁面的用戶openid的,並且是靜默授權並自動跳轉到回調頁的。用戶感知的就是直接進入了回調頁(往往是業務頁面) 以snsapi_userinfo為scope發起的網頁授權,是用來獲取用戶的基本資訊的。但這種授權需要用戶手動同意,並且由於用戶同意過,所以無須關注,就可在授權後獲取該用戶的基本資訊。 用戶管理類介面中的「獲取用戶基本資訊介面」,是在用戶和公眾號產生訊息交互或關注後事件推送後,才能根據用戶OpenID來獲取用戶基本資訊。這個介面,包括其他微信介面,都是需要該用戶(即openid)關注了公眾號後,才能呼叫成功的。 具體而言,網頁授權流程分為四步: 引導用戶進入授權頁面同意授權,獲取code 透過code換取網頁授權access_token(與基礎支援中的access_token不同) 如果需要,開發者可以重新整理網頁授權access_token,避免過期 透過網頁授權access_token和openid獲取用戶基本資訊(支援UnionID機制) 以下是封裝的微信操作類,需要用到兩個資料表,用於保存access_token、ticket,由於它們具有一定有效期,且每天請求數有上限,所以開發者需自行保存 <?php /\*\* \* 微信操作表 \* wxtoken 表結構 \* id \* access\_token \* addtime \* wxticket 表結構 \* id \* ticket \* addtime \*/ class WX { private $appid; private $appserect; private $curl; private $msg; protected $errs = array( '-1' => '系統繁忙,此時請開發者稍候再試', '0' => '請求成功', '40001' => 'AppSecret錯誤或者AppSecret不屬於這個公眾號,請開發者確認AppSecret的正確性', '40002' => '請確保grant\_type字段值為client\_credential', '40164' => '呼叫介面的IP地址不在白名單中,請在介面IP白名單中進行設定。', ); function \_\_construct($appid, $appserect) { $this->appid = $appid; $this->appserect = $appserect; $this->curl = new Curl(); } /\* 微信網頁授權登入 需要在公眾號設定 - 功能設定 - 網頁授權域名 第一步:用戶同意授權,獲取code scope : snsapi\_base 只能獲取openid 直接跳轉 snsapi\_userinfo \*/ public function getCode($redirect\_uri, $scope = 'snsapi\_userinfo',$state = '1') { $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appid}&redirect\_uri={$redirect\_uri}&response\_type=code&scope={$scope}&state={$state}#wechat\_redirect"; header("Location:{$url}"); exit; } /\* 第二步:透過code換取網頁授權access\_token \*/ public function getAccessTokenByCode($code) { $url = "https://api.weixin.qq.com/sns/oauth2/access\_token?appid={$this->appid}&secret={$this->appserect}&code={$code}&grant\_type=authorization\_code"; // exit($url); // $curl = new Curl(); $result = $this->curl->doGet($url); if (!$result) { // $this->curl->getError() $this->msg = "獲取token失敗"; return false; } $result = json\_decode($result, true); if ($result\['errcode'\]) { $this->msg = $result\['errmsg'\]; return false; } return $result; } // 第三步:重新整理access\_token(如果需要) 透過code 獲取openid $type 0靜默授權 1彈窗授權 public function getUserInfo($code, $type = 0, $lang = 'zh\_CN ') { $result = $this->getAccessTokenByCode($code); if (!$result) { return false; } $member = C::t(PT\_USER)->getByOpenid($result\['openid'\]); if ($member) { return $member; } else { if ($type) { $url = "https://api.weixin.qq.com/sns/userinfo?access\_token={$result\['access\_token'\]}&openid={$result\['openid'\]}&lang={$lang}"; // $return = $this->curl->doGet($url); // 這介面有病 強制顯示文件頭 $return = file\_get\_contents($url); if (!$return) { $this->msg = '獲取用戶資訊失敗'; return false; } $return = json\_decode($return, true); if (!$return) { $this->msg = '獲取用戶資訊返回失敗'; return false; } // file\_put\_contents('ccc.txt',print\_r($return,true),FILE\_APPEND); $data = array( 'openid' => $return\['openid'\], 'name' => $return\['nickname'\], 'sex' => $return\['sex'\], 'province' => $return\['province'\], 'city' => $return\['city'\], 'country' => $return\['country'\], 'img' => $return\['headimgurl'\], 'bindtel' => 0, ); } else { $data = array( 'openid' => $result\['openid'\], 'username' => "微信用戶\_" . random(6,1) ); } $name = rand(100000, 1000000000); $e = $name . "@qq.com"; $password = $e; $id = UserAddEdit(0, $data\['username'\], $password, $e,10,0,"", $msg); if ($id <= 0) { $this->msg = $msg; return false; } C::t(PT\_USER)->update($data, $id); $member = C::t(PT\_USER)->get($id); return $member; } } /\* 公眾號 安全中心 設定IP白名單 公眾號的全局唯一介面呼叫憑據,公眾號呼叫各介面時都需使用access\_token。開發者需要進行妥善保存。access\_token的儲存至少要保留512個字符空間。access\_token的有效期目前為2個小時,需定時重新整理,重複獲取將導致上次獲取的access\_token失效。 \*/ public function getAccessToken($type) { $addtime = TIMESTAMP - 7200; $url = "https://api.weixin.qq.com/cgi-bin/token?grant\_type=client\_credential&appid={$this->appid}&secret={$this->appserect}"; $row = C::t(PT\_WXTOKEN)->getNew($addtime, $type); if ($row) { return $row\['access\_token'\]; } else { $result = $this->curl->doGet($url); if (!$result) { $this->msg = "無法獲取令牌內容"; return false; } $result = json\_decode($result, true); if (!$result) { $this->msg = "解析令牌內容失敗"; return false; } if ($result\['access\_token'\]) { C::t(PT\_WXTOKEN)->addToken($result\['access\_token'\], $type); return $result\['access\_token'\]; } else { $this->msg = "獲取令牌失敗"; return false; } } } // 獲取js票據 需要在公眾號設定 - 功能設定 - JS介面安全域名設定 public function getJsTicket() { $addtime = TIMESTAMP - 7200; $row = C::t(PT\_WXTICKET)->getNew($addtime); if ($row) { return $row\['ticket'\]; } else { $token = $this->getAccessToken(); if (!$token) { return false; } $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access\_token={$token}&type=jsapi"; $result = $this->curl->doGet($url); if (!$result) { $this->msg = "無法獲取js票據"; return false; } $result = json\_decode($result, true); if (!$result) { $this->msg = "解析js票據內容失敗"; return false; } if ($result\['ticket'\]) { C::t(PT\_WXTICKET)->addTicket($result\['ticket'\]); return $result\['ticket'\]; } else { $this->msg = "獲取js票據失敗"; return false; } } } // js sdk 票據簽名 當前網頁的URL,不包含#及其後面部分 public function jsSign($data) { // 1.所有待簽名參數按照字段名的ASCII 碼從小到大排序(字典序) ksort($data); // 2.URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1 採用原始值,不進行URL 轉義 $string1 = $this->ToUrlParams($data); // echo "string1:{$string1}"; // 3.對string1做sha1加密 $sign = sha1($string1); // echo "signature:{$sign}"; return $sign; } // 獲取訊息內容 public function getMsg() { return $this->msg; } /\*\* \* 格式化參數格式化成url參數 \*/ public function ToUrlParams($data) { $buff = ""; foreach ($data as $k => $v) { if ($k != "sign" && $v != "" && !is\_array($v)) { $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff; } } ?> // 微信登入 function wxlogin() { global $_G,$identifier,$config,$wx; if (!$_G[‘uid’]) { if ($_GET[‘state’]) { // 回調 $member = $wx->getUserInfo($_GET[‘code’]); if (!$member) { exit($wx->getMsg()); } if (!function_exists(“setloginstatus”)) { include_once libfile(‘function/member’); } // 設定登入狀態$wx setloginstatus($member, 2592000); checkfollowfeed(); $_G[‘uid’] = $member[‘uid’]; $_G[‘member’] = $member; } else { // 請求授權 對參數編碼 $redirect = urlencode(getProtocol() . $_SERVER[‘HTTP_HOST’] . $_SERVER[‘REQUEST_URI’]); $wx->getCode($redirect, ‘snsapi_base’); } } } function getProtocol() { return is_HTTPS() ? ‘https://’ : ‘http://’; } function is_HTTPS() { if ($_SERVER[‘HTTPS’] === 1 || $_SERVER[‘HTTPS’] === ‘on’ || $_SERVER[‘SERVER_PORT’] == 443) { return true; } return false; }

2019年4月5日 · 4 min · MoeJue

微信JSAPI支付

前陣子一直在做微信相關的業務,雖說不是什麼新技術,但之前一直沒有機會接觸到,然後踩了些坑,抽空整理記錄下。 微信支付一共分為7種,分別是:付款碼支付、JSAPI支付、Native支付、APP支付、H5支付、小程序支付、人臉支付。 此次業務中使用到的是微信JSAPI支付:用戶透過微信掃碼、關注公眾號等方式進入商家H5頁面,並在微信內呼叫 JSSDK完成支付 文件:https://pay.weixin.qq.com/wiki/doc/api/index.html SDK:[https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1 ](https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1)JSAPI支付需要在微信中的瀏覽器打開才能喚起微信支付,效果如下圖 附上介面程式碼 程式碼中使用了模板引擎 html: {$competition\['username'\]} {$prices\[0\]}鑽 {$prices\[1\]}鑽 {$prices\[2\]}鑽 {$prices\[3\]}鑽 {$prices\[4\]}鑽 註:1鑽=1元,1鑽={$activity\['offset'\]}票 立即微信支付 JavaScript: // 投票 var offset = {$activity[‘offset’]}; $(’#tips’).html(‘正在給{$competition[‘code’]}號贈送{$prices[0]}鑽=’+({$prices[0]}*offset)+‘票’); $(’#vote’).click(function(){ $.post(’/index/index/detailed.html?cid={$cid}&aid={$aid}’,{ formhash :’{FORMHASH}’, submit:‘1’, type:1, openid:’{$_G[‘member’][‘openid’]}’ },function(res){ alert(res.msg); if (res.code == 0) { $(’.box-1 span’).text(res.data.all); $(’.box-2 span’).text(res.data.rank); $(’.box-3 span’).text(res.data.up + ‘票’); } }); }) /* jQuery物件級別外掛程式擴展 */ $.fn.extend({ /* 單選框 */ hlRadio:function () { var radioEl=$(this); radioEl.click(function () { var price = 0; price = $(‘input:radio:checked’).val(); $(’#price’).val(’’); $(’#tips’).html(‘正在給{$competition[‘code’]}號贈送’+price+‘鑽=’+(price*offset)+‘票’); radioEl.siblings(“div”).removeClass(“active”); $(this).siblings(“div”).addClass(“active”); }); }, }); $(“input[name=‘price’]”).hlRadio(); $(’#price’).bind(‘input propertychange’, function(){ var price = 0; price = $(’#price’).val(); $(’#tips’).html(‘正在給{$competition[‘code’]}號贈送’+price+‘鑽=’+(price*offset)+‘票’); }) ...

2019年3月30日 · 4 min · MoeJue