


Développement du matériel WeChat H5 pour contr?ler les lumières
Mar 16, 2018 pm 02:27 PM這次給大家?guī)砦⑿庞布﨟5開發(fā)之控制燈光,微信硬件H5開發(fā)控制燈光的注意事項有哪些,下面就是實戰(zhàn)案例,一起來看一下。
你可以自己扒,帶參數(shù)的頁面在瀏覽器中打開會馬上跳轉(zhuǎn),不帶參數(shù)的會提示參數(shù)不全,需要用mobile模式觀看。
呈現(xiàn)的界面如下:
目錄結(jié)構(gòu)?
解壓開lamp.js ,目錄如下,這個demo是基于sea.js+zepto實現(xiàn),sea.js用來加載模塊,zepto提供ajax請求和tab事件等。
common中包含了一個keyConfig.js(地址參數(shù)),一個reqData.js(請求封裝)還有一個zepto,ui里是一個上面圖片的中的slider一樣的組件。util中是一組方法集合。最重要的就是lamp.js 。
define(function?(require)?{????var?$?=?require("common/zepto");????var?keyConfig?=?require("common/keyConfig");????var?reqData?=?require("common/reqData");????var?util?=?require("util/util");????var?ProcessBar?=?require("ui/process-bar");????var?pageParam?=?{ ????????device_id:?util.getQuery("device_id"), ????????device_type:?util.getQuery("device_type"), ????????appid:?util.getQuery("appid") ????};????var?lastModTime?=?0;????var?powerBtn?=?$("#powerBtn"),?//?開關(guān)按鈕????????lightBar;????var?device_status=?{ ????????services:?{ ????????????lightbulb:?{alpha:0}, ????????????operation_status:{status:0} ????????} ????};?//?數(shù)據(jù)對象 ????(function?()?{????????if(!pageParam.device_id?||?!pageParam.device_type){ ????????????alert("頁面缺少參數(shù)");????????????return; ????????} ????????log("appid:"?+?pageParam.appid); ????????log("device_id:"?+?pageParam.device_id); ????????log("device_type:"?+?pageParam.device_type); ????????powerBtn.on("tap",?togglePower);?//?開關(guān)按鈕事件????????initBar(); ????????initInterval();????????//?todo?:?for?test,?delete?before?submit//????????renderPage({});????})();????/** ?????*?初始化進度條?????*/ ????function?initBar()?{ ????????log("初始化lightBar"); ????????lightBar?=?new?ProcessBar({ ????????????$id:?"lightBar", ????????????min:?0, ????????????stepCount:?100, ????????????step:?1, ????????????touchEnd:?function?(val)?{ ????????????????device_status.services.lightbulb.alpha?=?val; ????????????????log("亮度值為:"+val);????????????????setData(); ????????????} ????????}); ????}????/** ?????*?請求數(shù)據(jù)?????*/ ????function?getData()?{ ????????reqData.ajaxReq({????????????//url:?keyConfig.GET_LAMP_STATUS, ????????????url:'https://api.weixin.qq.com/device/getlampstatus', ????????????data:?pageParam, ????????????onSuccess:?renderPage, ????????????onError:function(msg)?{ ????????????????log("獲取數(shù)據(jù)失敗:"?+?JSON.stringify(msg)); ????????????} ????????}); ????}????/** ?????*?設(shè)置數(shù)據(jù)?????*/ ????function?setData()?{ ????????console.log("setUrl",?keyConfig.SET_LAMP_STATUS); ????????lastModTime?=?new?Date().getTime();?//?更新最后一次操作時間????????reqData.ajaxReq({???????????//?url:?keyConfig.SET_LAMP_STATUS, ????????????url:?'https://api.weixin.qq.com/device/setlampstatus', ????????????type:?"POST", ????????????data:?JSON.stringify(device_status) ????????}); ????????log("setData:"?+?JSON.stringify(device_status)); ????}????/** ?????*?開關(guān)按鈕事件?????*/ ????function?togglePower()?{ ????????$("#switchBtn").toggleClass("on").toggleClass("off"); ????????log("燈的狀態(tài)status:"+device_status.services.operation_status.status);????????if(device_status.services.operation_status.status==0){ ????????????device_status.services.operation_status.status?=?1; ????????????log("燈的狀態(tài):1"); ????????}?else?{ ????????????device_status.services.operation_status.status?=?0; ????????????log("燈的狀態(tài):0"); ????????}????????setData(); ????}????/** ?????*?輪詢?????*/ ????function?initInterval()?{ ????????getData(); ????????setInterval(function?()?{????????????if((new?Date().getTime()?-?lastModTime)?>?2000){?//?當有設(shè)置操作時,停止1s輪詢,2秒后繼續(xù)輪詢????????????????getData(); ????????????} ????????},?1000); ????}????/** ?????*?渲染頁面?????*/ ????function?renderPage(json)?{????????//?todo?:?for?test,?delete?before?submit//????????json?=?{//????????????device_status:?{//????????????????services:?{//????????????????????operation_status:?{//????????????????????????status:?0//????????????????????},//????????????????????lightbulb:?{//????????????????????????alpha:?0//????????????????????}//????????????????}//????????????}//????????}; ????????log("renderPage:"+json);????????if(!json.device_status){????????????return; ????????} ????????console.log("json",?json); ????????device_status?=?json.device_status; ????????log(device_status);????????if(device_status.services.operation_status.status==0){ ????????????$("#switchBtn").addClass("on").removeClass("off"); ????????}?else?{ ????????????$("#switchBtn").addClass("off").removeClass("on"); ????????} ????????lightBar.setVal(device_status.services.lightbulb.alpha); ????} });/*??|xGv00|4199711a9ade00e2807e7ea576d92f55?*/
?首先我們看到pageParam對象是獲取頁面上參數(shù)的,device_id,device_type以及appid三個參數(shù)。其實有用的只有前面兩個,因為appid的話,后臺服務(wù)器已經(jīng)配置了,而且在微信中的通過“進入面板”的時候只附帶了id和type兩個參數(shù)。然后device_status是一個設(shè)備狀態(tài)對象對象是燈,根據(jù)微信services的定義,燈有一個亮度值。這個在上一篇提到過。然后是一個立即執(zhí)行的匿名函數(shù),這個函數(shù)函數(shù)里面會先檢查一下參數(shù),然后初始化開關(guān)和亮度條。最好進入循環(huán)。initInterval中就是不斷的通過getdata獲取數(shù)據(jù)。注意到這兒有一個lastModTime的比較,然后延時2秒再觸發(fā),這個地方主要是因為每次設(shè)置之后再從服務(wù)器撈到數(shù)據(jù)有一個延時。原本是10,你設(shè)置了20,bar也到了20的位置,但是呢,服務(wù)器還有一個10在路上發(fā)過來,你設(shè)置的20并沒有馬上失效,這會有一個卡頓的效果。但這個兩秒也不是那么的有效,卡頓還是會有;另外一方面就是,不能設(shè)置太快,設(shè)置太快了會報50019的錯誤(設(shè)備正在被操作);getdata成功后,就是renderpage,這個不用解釋了。注意到在綁定開關(guān)時間的地方,其實是先調(diào)用了一次setdata
?powerBtn.on("tap",?togglePower);?function?togglePower()?{ ????????$("#switchBtn").toggleClass("on").toggleClass("off"); ????????log("燈的狀態(tài)status:"+device_status.services.operation_status.status);????????if(device_status.services.operation_status.status==0){ ????????????device_status.services.operation_status.status?=?1; ????????????log("燈的狀態(tài):1"); ????????}?else?{ ????????????device_status.services.operation_status.status?=?0; ????????????log("燈的狀態(tài):0"); ????????}????????setData(); ????}
?這個作用有兩個,一個是獲取設(shè)備目前的狀態(tài),因為設(shè)備可能沒有開啟,或者沒有聯(lián)網(wǎng),二個是將參數(shù)傳遞給后臺,不然getdata無效。最后理清一下思路就是
獲取參數(shù)-->初始化-->setdata一次-->循環(huán)-->渲染頁面 ?界面操作-->setdata-->延時讀取。 加上后端的部分,全部的流程圖如下。
所以拿到前端代碼只是一半,后端還需要自己實現(xiàn)。
實現(xiàn)
純靜態(tài)文件是無法請求微信服務(wù)器的,所以我們需要自己實現(xiàn)后臺的部分,這也是第一節(jié)中要講的目的。
html:
@{ ????Layout?=?null; }<!DOCTYPE html><html><head> ????<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> ????<meta id="viewport" name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> ????<title>我的燈泡</title> ????<link href="/css/common.css" rel="stylesheet" /> ????<link href="/css/light_switch.css" rel="stylesheet" /></head><body> ????<p> ????????<p class="body"> ????????????<p class="inner"> ????????????????<p id="switchBtn" class="status_button off"> ????????????????????<p class="button_wrp"> ????????????????????????<p class="button_mask"> ????????????????????????????<p class="alerter_button" id="powerBtn"> ????????????????????????????????<i class="status_pot"></i> ????????????????????????????????<span class="on">ON</span> ????????????????????????????????<span class="off">OFF</span> ????????????????????????????</p> ????????????????????????</p> ????????????????????</p> ????????????????????<p class="on"> ????????????????????????<h2>燈已開</h2> ????????????????????</p> ????????????????</p> ????????????????<p id="reData"></p> ????????????</p> ????????</p> ????????<p class="foot"> ????????????<p class="slider_box J_slider_box"> ????????????????<i class="slider_box_icon icon dark"></i> ????????????????<p id="lightBar" class="slider_box_bar"> ????????????????????<p class="slider_box_slider J_slider" style="left:0%"> ????????????????????????<p class="slider_box_slider_label J_value"></p> ????????????????????????<i class="slider_box_slider_touch"></i> ????????????????????</p> ????????????????????<p class="slider_box_line"> ????????????????????????<span class="slider_box_line_fill J_fill" style="width:0%"></span> ????????????????????</p> ????????????????</p> ????????????????<i class="slider_box_icon icon light"></i> ????????????</p> ????????</p> ????</p> ????<script src="/js/sea.js"></script> ????<script> ????????seajs.config({ ????????????base:?'/js/',????????????//map:?[[/^(.*\.(?:css|js))(.*)$/i,?"$1"]],????????????charset:?'utf-8' ????????}); ????????seajs.use("baby");????</script></body></html>
View Code
自己的實現(xiàn)就拿掉了遮罩和config部分,將sea.js的目錄改到自己對應(yīng)的目錄即可:
???seajs.config({ ????????????base:?'/js/',????????????//map:?[[/^(.*\.(?:css|js))(.*)$/i,?"$1"]], ????????????charset:?'utf-8' ????????}); ????????seajs.use("baby");
這個baby(命名和產(chǎn)品有關(guān)~)就相當于是lamp。 另外就是,修改請求地址。也就是通過后臺調(diào)用api來實現(xiàn)getdate和setdata。第一版我修改的js和lamp.js的差別不大 就增加了一個log為了調(diào)試,修改調(diào)用路徑。
define(function?(require)?{????var?$?=?require("common/zepto");????var?util?=?require("util/util");????var?ProcessBar?=?require("ui/process-bar");?? ????var?requestData?=?{ ????????services:?{ ????????????lightbulb:?{?alpha:?10?}, ????????????air_conditioner:?{}, ????????????power_switch:?{}, ????????????operation_status:?{?status:?0?} ????????}, ????????device_type:?util.getQuery("device_type"), ????????device_id:?util.getQuery("device_id"), ????????user:?'', ????};????var?lastModTime?=?0;????var?powerBtn?=?$("#powerBtn"),?//?開關(guān)按鈕???????lightBar;????function?log(msg,?arg)?{ ????????console.log(msg,?arg); ????????msg?=?JSON.stringify(msg);????????if?(arg)?{ ????????????msg?=?msg?+?","?+?JSON.stringify(arg); ????????} ????????$.post('/device/log',?{?msg:?msg?}); ????} ????(function?()?{ ????????bindEvent();????????if?(!requestData.device_id?||?!requestData.device_type)?{ ????????????alert("頁面缺少參數(shù)");????????????return; ????????} ????????powerBtn.on("tap",?togglePower);?//?開關(guān)按鈕事件????????initBar(); ????????queryDevice(); ????})();????function?bindEvent()?{ ????????$(".footer?.nav_side?li").click(function?()?{ ????????????activePage($(this).data("index"),?$(this)); ????????}); ????}????function?activePage(index,?$self)?{ ????????$self.parent('li').addClass("on"); ????????$body.find('.page:eq('?+?index?+?')').addClass("active").siblings().removeClass("active"); ????}????/** ?????*?初始化進度條?????*/ ????function?initBar()?{ ????????log("初始化lightBar"); ????????lightBar?=?new?ProcessBar({ ????????????$id:?"lightBar", ????????????min:?0, ????????????stepCount:?100, ????????????step:?1, ????????????touchEnd:?function?(val)?{ ????????????????requestData.services.lightbulb.alpha?=?val; ????????????????log("亮度值為:"?+?val); ????????????????setData(); ????????????} ????????}); ????}????/** ???*?開關(guān)按鈕事件???*/ ????function?togglePower()?{ ????????$("#switchBtn").toggleClass("on").toggleClass("off");????????if?(requestData.services.operation_status.status?==?0)?{ ????????????requestData.services.operation_status.status?=?1; ????????????log("燈的狀態(tài):1"); ????????}?else?{ ????????????requestData.services.operation_status.status?=?0; ????????????log("燈的狀態(tài):0"); ????????} ????????setData(); ????}????function?queryDevice()?{ ????????$.getJSON('/device/RequestDeviceStatus',?{?reqstr:?JSON.stringify(requestData)?},????????????function?(data)?{ ????????????????console.log(data);????????????????if?(data.error_code?==?0)?{????????????????????//請求成功;????????????????????initInterval(); ????????????????????console.log("查詢成功"); ????????????????}?else?{ ????????????????????alert(data.error_msg); ????????????????} ????????????}); ????}????/** ???*?輪詢???*/ ????function?initInterval()?{ ????????getData(); ????????setInterval(function?()?{????????????if?((new?Date().getTime()?-?lastModTime)?>?2000)?{?//?當有設(shè)置操作時,停止1s輪詢,2秒后繼續(xù)輪詢????????????????getData(); ????????????} ????????},?1000); ????}????function?setData()?{ ????????$.getJSON('/device/RequestDeviceStatus',?{?reqstr:?JSON.stringify(requestData)?},?function?(data)?{ ????????????console.log(data); ????????????lastModTime?=?new?Date().getTime();????????????if?(data.error_code?==?0)?{ ????????????????console.log("設(shè)置成功"); ????????????} ????????}); ????}????function?getData()?{ ????????$.post('/device/getData',?function?(data)?{ ????????????$("#reData").html(JSON.stringify(data));????????????if?(data?&&?data.services)?{ ????????????????renderPage(data); ????????????} ????????}); ????};????function?renderPage(json)?{????????if?(!json.services)?{????????????return; ????????} ????????console.log("json",?json); ????????requestData?=?json;????????if?(requestData.services.operation_status.status?==?0)?{ ????????????$("#switchBtn").addClass("off").removeClass("on"); ????????}?else?{ ????????????$("#switchBtn").addClass("on").removeClass("off"); ????????} ????????lightBar.setVal(requestData.services.lightbulb.alpha); ????} })
View Code
?我將pageParam和device_status做成了一個對象。requestData。
????var?requestData?=?{ ????????services:?{ ????????????lightbulb:?{?alpha:?10?},???????????//?air_conditioner:?{},????????????power_switch:?{}, ????????????operation_status:?{?status:?0?} ????????}, ????????device_type:?util.getQuery("device_type"), ????????device_id:?util.getQuery("device_id"), ????????user:?'', ????};
后臺就是兩個主要方法,一個設(shè)置(查詢頁就是設(shè)置),一個讀取。這里又回到上一節(jié)的內(nèi)容了。我先查詢一次設(shè)備(lamp中在綁定)之后,再進入循環(huán)。
setdata
public?ActionResult?RequestDeviceStatus(string?reqstr) ????????{????????????if?(string.IsNullOrEmpty(reqstr)) ????????????{????????????????return?Json("-1",?JsonRequestBehavior.AllowGet); ????????????}????????????var?args?=?JsonConvert.DeserializeObject<RequestData>(reqstr); ????????????args.user?=?getOpenId(args.device_type,?args.device_id); ????????????Session["warmwood"]?=?args.device_id;????????????//args.services.air_conditioner?=?null; ????????????args.services.power_switch?=?null; ????????????args.services.lightbulb.value_range?=?null;????????????try ????????????{????????????????var?res?=?wxDeviceService.RequestDeviceStatus(getToken(),?args);????????????????if?(res.error_code?!=?0) ????????????????{ ????????????????????Logger.Debug("error_code:"?+?res.error_code); ????????????????????Logger.Debug("error_msg:"?+?res.error_msg); ????????????????}????????????????return?Json(res,?JsonRequestBehavior.AllowGet); ????????????}????????????catch?(ErrorJsonResultException?e) ????????????{????????????????if?(e.JsonResult.errcode.ToString()?==?"access_token?expired") ????????????????{????????????????????//重新獲取token????????????????} ????????????????Logger.Debug("請求失?。?quot;?+?e.Message); ????????????}????????????return?Json("-1",?JsonRequestBehavior.AllowGet); ????????}
這個方法先將字符串轉(zhuǎn)成我們的RequestData對象,RequestData如下:
????public?class?RequestData ????{????????public?string?device_type?{?get;?set;?}????????public?string?device_id?{?get;?set;?}????????public?string?user?{?get;?set;?}????????public?Service?services?{?get;?set;?}????????public?object?data?{?get;?set;?} ????}
services就是根據(jù)微信services定義的,可以參考上一節(jié),然后用wxDeviceService請求。
?var?res?=?wxDeviceService.RequestDeviceStatus(getToken(),?args);????????????????if?(res.error_code?!=?0) ????????????????{ ????????????????????Logger.Debug("error_code:"?+?res.error_code); ????????????????????Logger.Debug("error_msg:"?+?res.error_msg); ????????????????}???return?Json(res,?JsonRequestBehavior.AllowGet);
設(shè)置之后馬上會受到是否設(shè)置成功的響應(yīng),error_code 可能為50019(設(shè)置頻繁),50013(網(wǎng)絡(luò)問題)等等。真正的設(shè)備狀態(tài)是通過getdata獲得的。
getdata
????????public?JsonResult?GetData() ????????{????????????var?userdata?=?getUserWxData();????????????return?Json(userdata.ResponseData,?JsonRequestBehavior.AllowGet); ????????}
getdata比較簡單就是返回數(shù)據(jù),但是這個數(shù)據(jù)是在ReceiveWXMsg方法中設(shè)置的。這個上一節(jié)也講過,這是在公眾號后臺我們設(shè)置的一個地址。
???public?string?ReceiveWXMsg() ????????{ ????????????//somecode ????????????try ????????????{????????????????var?userdata?=?getUserWxData();????????????????var?data?=?wxDeviceService.GetDeviceStatus(Request); ????????????????userdata.ResponseData?=?data; ????????????????Logger.Debug("ResponseData.asy_error_code:"?+?userdata.ResponseData.asy_error_code); ????????????????Logger.Debug("ResponseData.asy_error_msg:"?+?userdata.ResponseData.asy_error_msg); ????????????????setUserWxData(userdata); ????????????}????????????catch?(Exception?e) ????????????{ ????????????????Logger.Debug(e.Message); ????????????}????????????return?echostr; ????????}
wxDeviceService如下:
using?System;using?System.Collections.Generic;using?System.Diagnostics;using?System.IO;using?System.Linq;using?System.Net.Http;using?System.Web;using?Newtonsoft.Json;using?Niqiu.Core.Domain.Common;using?Senparc.Weixin;using?Senparc.Weixin.Exceptions;using?SendHelp=?Senparc.Weixin.CommonAPIs.CommonJsonSend;namespace?Portal.MVC.WXDevice {????public?class?WxDeviceService:IWxDeviceService ????{????????//private?readonly?ICacheManager?_cacheManager;????????//public?WxDeviceService(ICacheManager?cacheManager)????????//{????????//????_cacheManager?=?cacheManager;????????//} ????????public?TokenResult?GetAccessToken() ????????{????????????var?url?=?string.Format(WxDeviceConfig.AccessTokenUrl,?WxDeviceConfig.AppId,?WxDeviceConfig.APPSECRET);????????????var?res?=?SendHelp.Send<TokenResult>(null,?url,?null,?CommonJsonSendType.GET);????????????return?res; ????????}????????public?WxResponseData?GetDeviceStatus(HttpRequestBase?request) ????????{ ????????????Stream?postData?=?request.InputStream; ????????????StreamReader?sRead?=?new?StreamReader(postData);????????????string?postContent?=?sRead.ReadToEnd();????????????if?(!string.IsNullOrEmpty(postContent)) ????????????{ ????????????????Logger.Debug("收到數(shù)據(jù):"?+?postContent); ????????????}????????????try ????????????{????????????????var?data?=?JsonConvert.DeserializeObject<WxResponseData>(postContent); ????????????????data.rawStr?=?postContent; ????????????????Logger.Debug("轉(zhuǎn)換消息狀態(tài):"?+?data.asy_error_msg);????????????????return?data; ????????????}????????????catch?(Exception?e) ????????????{ ????????????????Logger.Debug(e.Message);????????????????throw; ????????????} ????????}????????public?OpenApiResult?RequestDeviceStatus(string?accessToken,?RequestData?data) ????????{????????????var?url?=?string.Format(WxDeviceConfig.GetDeviceStatusUrl,?accessToken);????????????return?SendHelp.Send<OpenApiResult>(accessToken,?url,?data); ????????}????????public?OpenApiResult?SetDevice(string?accessToken,?RequestData?data) ????????{????????????var?url?=?string.Format(WxDeviceConfig.GetDeviceStatusUrl,?accessToken);????????????return?SendHelp.Send<OpenApiResult>(accessToken,?url,?data); ????????}????????public?string?GetOpenId(string?accessToken,string?deviceType,string?deviceId) ????????{????????????try ????????????{????????????????var?url?=?string.Format(WxDeviceConfig.GetOpenid,?accessToken,?deviceType,?deviceId);????????????????var?res?=?SendHelp.Send<OpenIdResult>(accessToken,?url,?null,?CommonJsonSendType.GET);????????????????return?res.GetOpenId(); ????????????}????????????catch?(ErrorJsonResultException?e) ????????????{ ????????????????Logger.Debug(e.Message);????????????????throw; ????????????} ????????} ????} }
View Code
這方法讀到數(shù)據(jù)后就交給了userdata 緩存起來。在getdata方法中返回。
???private?UserWxData?getUserWxData() ????????{????????????var?target?=?_cacheManager.Get<UserWxData>(userKey)????new?UserWxData();????????????return?target; ????????}????????private?string?userKey ????????{????????????get ????????????{????????????????var?key?=?Session["warmwood"]????Session.SessionID; ????????????????Session.Timeout?=?240;????????????????return?key.ToString(); ????????????} ????????}
View Code
UserWxData是我自定義的對象,包含了下面的幾個熟悉。
????public?class?UserWxData ????{????????private?WxResponseData?_responseData;????????public?UserWxData() ????????{ ????????????CreateTime?=?DateTime.Now; ????????}????????public?DateTime?CreateTime?{?get;?set;?}????????public?TokenResult?AccessToken?{?get;?set;?}????????public?WxResponseData?ResponseData ????????{????????????get?{?return?_responseData??(_responseData=new?WxResponseData());?}????????????set?{?_responseData?=?value;?} ????????}????????public?string?OpenId?{?get;?set;?} ????}
比較重要的是token和responseData。WxResponseData 也就是最終要發(fā)給頁面上的對象。包含你需要的功能的參數(shù)。
?public?class?WxResponseData ????{????????public?int?asy_error_code?{?get;?set;?}????????public?string?asy_error_msg?{?get;?set;?}????????public?string?create_time?{?get;?set;?}????????public?string?msg_id?{?get;?set;?}????????///?<summary> ????????///?notify?說明是設(shè)備變更????????///?set_resp?說明是設(shè)置設(shè)備????????///?get_resp?說明獲取設(shè)備信息????????///?</summary> ????????public?string?msg_type?{?get;?set;?}????????public?string?device_type?{?get;?set;?}????????public?string?device_id?{?get;?set;?}????????public?object?data?{?get;?set;?}????????public?Service?services?{?get;?set;?}????????public?string?user?{?get;?set;?}????????public?string?rawStr?{?get;?set;?} ????}
severices看自己的設(shè)備定義,比如我現(xiàn)在包含了空調(diào),開關(guān),溫度濕度。
????public?class?Service ????{????????public?lightbulb?lightbulb?{?get;?set;?}????????public?air_conditioner?air_conditioner?{?get;?set;?}????????public?power_switch?power_switch?{?get;?set;?}????????public?operation_status?operation_status?{?get;?set;?}????????public?tempe_humidity?tempe_humidity?{?get;?set;?} ????}
到這兒,整個過程就講完了,獲取token和openid上一節(jié)講過,就不贅述了。如果后端是node的話,就不需要這么多的類型轉(zhuǎn)換了。
最后可以看下效果:
相信看了本文案例你已經(jīng)掌握了方法,更多精彩請關(guān)注php中文網(wǎng)其它相關(guān)文章!
推薦閱讀:
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undress AI Tool
Images de déshabillage gratuites

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
échangez les visages dans n'importe quelle vidéo sans effort grace à notre outil d'échange de visage AI entièrement gratuit?!

Article chaud

Outils chauds

Bloc-notes++7.3.1
éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Lorsque vous utilisez HTML5SSE, les méthodes pour gérer la reconnexion et les erreurs incluent: 1. Comprendre le mécanisme de reconnexion par défaut. Eventsource réessayer 3 secondes après l'interrompu de la connexion par défaut. Vous pouvez personnaliser l'intervalle via le champ de réessayer; 2. écoutez l'événement d'erreur pour gérer les erreurs de défaillance de connexion ou d'analyse, distinguer les types d'erreurs et exécuter la logique correspondante, telles que les problèmes de réseau en s'appuyant sur la reconnexion automatique, les erreurs de serveur retardent manuellement la reconnexion et la défaillance de l'échec d'authentification Rafra?chissement du jeton; 3. Contr?lez activement la logique de reconnexion, telle que la fermeture et la reconstruction manuelle de la connexion, en définissant le nombre maximum de temps de réessayer, combinant Navigator.online pour juger l'état du réseau pour optimiser la stratégie de réessayer. Ces mesures peuvent améliorer la stabilité des applications et l'expérience utilisateur.

HTML5, CSS et JavaScript doivent être combinés efficacement avec des balises sémantiques, un ordre de chargement raisonnable et une conception de découplage. 1. Utilisez des étiquettes sémantiques HTML5, telles que l'amélioration de la clarté structurelle et de la maintenabilité, qui est propice au référencement et à l'accès sans barrière; 2. CSS doit être placé, utiliser des fichiers externes et se séparer par module pour éviter les styles en ligne et les problèmes de chargement retardés; 3. JavaScript est recommandé d'être introduit à l'avant et d'utiliser un repère ou une asynchronisation pour charger de manière asynchrone pour éviter le blocage du rendu; 4. Réduisez une forte dépendance entre les trois, conduisez le comportement à travers les attributs de données * et l'état de contr?le du nom de classe et améliorez l'efficacité de la collaboration grace à des spécifications de nommage unifiées. Ces méthodes peuvent optimiser efficacement les performances des pages et collaborer avec les équipes.

Doctype est une déclaration qui indique au navigateur quelle norme HTML à utiliser pour analyser la page. Les pages Web modernes ne doivent être écrites qu'au début du fichier HTML. Sa fonction est de s'assurer que le navigateur rend la page en mode standard plut?t qu'en mode bizarre, et doit être situé sur la première ligne, sans espaces ni commentaires devant lui; Il n'y a qu'une seule fa?on correcte de l'écrire, et il n'est pas recommandé d'utiliser d'anciennes versions ou d'autres variantes; D'autres tels que le marbre, la fenêtre, etc. doivent être placés en partie.

L'utilisation de balises sémantiques HTML5 et de microdata peut améliorer le référencement car elle aide les moteurs de recherche à mieux comprendre la structure des pages et la signification du contenu. 1. Utilisez des balises sémantiques HTML5 telles que ,,,, et pour clarifier la fonction des blocs de page, ce qui aide les moteurs de recherche à établir un modèle de page plus précis; 2. Ajoutez des données structurées microdata pour marquer un contenu spécifique, tel que l'auteur de l'article, la date de sortie, le prix du produit, etc., afin que les moteurs de recherche puissent identifier les types d'informations et les utiliser pour l'affichage du résumé des médias riches; 3. Faites attention à l'utilisation correcte des étiquettes pour éviter la confusion, évitez les balises en double, testez l'efficacité des données structurées, mettez régulièrement à mettre à jour pour s'adapter aux changements de schéma.org et combiner avec d'autres moyens de référencement pour optimiser à long terme.

Il s'agit d'un élément au niveau du bloc, adapté à la mise en page; Il s'agit d'un élément en ligne, adapté à l'emballage du contenu texte. 1. Occuper exclusivement une ligne, une largeur, une hauteur et des marges peuvent être définies, qui sont souvent utilisées dans la disposition structurelle; 2. Aucune ligne ne se casse, la taille est déterminée par le contenu et convient aux styles de texte locaux ou aux opérations dynamiques; 3. Lors du choix, il doit être jugé en fonction de la question de savoir si le contenu a besoin d'espace indépendant; 4. Il ne peut pas être imbriqué et ne convient pas à la mise en page; 5. La priorité est donnée à l'utilisation des étiquettes sémantiques pour améliorer la clarté structurelle et l'accessibilité.

MSE (MediaSourceExtensions) fait partie de la norme W3C, permettant à JavaScript de construire dynamiquement des flux de médias, permettant ainsi des capacités de lecture vidéo avancées. Il gère les sources multimédias via MediaSource, stocke les données de SourceBuffer et représente la plage de temps tampon par Timeranges, permettant au navigateur de charger et de décoder dynamiquement des clips vidéo. Le processus d'utilisation de MSE comprend: ① Créer une instance MediaSource; ② Le lier à un élément; ③ Ajouter SourceBuffer pour recevoir des données dans un format spécifique; ④ Obtenez des données segmentées via fetch () et ajoutez-les au tampon. Les précautions courantes comprennent: ① Problèmes de compatibilité du format; ② Paire de coups horaires

HTML5Introduit newinputTypesthatenHanceFormFonctionality andUserexperiendByImprovingValidation, UI, andmobilekeyboardlayouts.1.emailvalidateSemailAddressAndSupportsMultiplentries.2.urlchecksforvalidwebaddressandtriggersurl-optimizedkeyboard

Il est plus pratique de soumettre des données de formulaire à l'aide de l'API FormData de HTML5. 1. Il peut collecter automatiquement les champs de formulaire avec l'attribut de nom ou ajouter manuellement des données; 2. Il prend en charge la soumission au format multipart / format de format de format via Fetch ou XMLHTTPRequest, qui convient au téléchargement de fichiers; 3. Lors du traitement des fichiers, vous n'avez qu'à ajouter le fichier pour formerdata et envoyer une demande; 4. Notez que le champ du même nom sera écrasé et que la conversion JSON et aucune structure de nidification ne doivent être manipulées.
