亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

微信小程序 框架詳解及實例應用

2019-11-20 08:52:40
字體:
來源:轉載
供稿:網友

快速了解微信小程序的使用,一個根據小程序的框架開發的todos app

微信官方已經開放微信小程序的官方文檔和開發者工具。前兩天都是在看相關的新聞來了解小程序該如何開發,這兩天官方的文檔出來之后,趕緊翻看了幾眼,重點了解了一下文檔中框架與組件這兩個部分,然后根據簡易教程,做了一個常規的todo app。這個app基于微信小程序的平臺,實現了todo app的常規功能,同時為了讓它更接近實際的工作場景,也用到了loading與toast這兩個組件來完成一些操作的交互與反饋。這個平臺給我的直觀感受是,技術層面,它跟vue有相似性,但是遠沒有vue強大;開發時候的思路,不像vue,反倒覺得比較像backbone。所以要是使用過backbone,vue等mvc,mvvm框架的人,會覺得這個平臺上手很容易。本文主要介紹這個todo app實現的一些要點。

先補充下本文相關的資料:

官方文檔:https://mp.weixin.qq.com/debug/wxadoc/dev/index.html

官方開發者工具下載:https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html

本文todo app的功能演示:

注:需長按todo的text,才能直接編輯。因為是在手機端,所以不能使用雙擊事件來進行編輯,改成了長按事件。小程序的平臺也沒有提供雙擊事件的綁定。

相關源碼:https://github.com/liuyunzhuge/blog/tree/master/todos/wx

如果你想在本地運行這個項目,需要先安裝開發者工具,按照文檔中簡易教程的描述,先建好一個項目;
建完之后,開發者工具就會打開這個項目;
接著在磁盤上,找到建好的項目的文件夾,把里面的內容都刪掉,把上面源碼文件夾下的文件都粘貼進去;
然后重新打開開發者工具,先進入到編輯頁簽,然后點擊編譯按鈕,就會直接進入到調試界面,查看app的功能:

下面來介紹下這個app開發的要點:

1. 這個app的目錄結構以及配置等就不詳細介紹了,這些在文檔-框架部分都有很詳細的描述。這個平臺里面沒有html和css,取而代之的是wxml和wxss。wxss跟css幾乎沒有區別,缺點就是不如css強大,支持的選擇器有限。但是好處是由于只有微信這一個平臺,所以幾乎沒有兼容性問題,能夠使用標準的,更新的css技術。wxml里面只能用平臺提供的那些組件的標簽,html的標簽不能直接用,各個組件的在wxml的使用方式,都可以在文檔-組件這一部分找到說明的示例。所以實際上wxml跟wxss編寫起來都沒有什么難題。

2. wxml支持以下這些特性:

在todo app里面除了模板和引用沒有用到之外,其它的都使用到了,不過沒有使用到每個特性的各個細節,只根據app的需要選用合適的功能。前幾天看到有文章說,微信小程序可能是基于vue框架來實現的,所以就看了下vue的文檔。對于數據綁定,條件渲染,列表渲染,事件這幾部分都詳細看了vue的用法。對比下來,wxml提供的這些特性,跟vue的相關特性是還比較像,不過功能并沒有那么多,所以也不能輕易地直接拿vue框架的特性用到小程序里面。最佳實踐,還是基于官方文檔中提供的說明來,如果官方文檔中沒有提到的功能,通過猜測的方式去用,肯定是行不通的。我通過打印的方式,查看一些對象的原型,也并沒有發現比官方文檔要多的一些實例方法,說明小程序的框架功能確實是有限的。

3. wxss其實是可以用less或者sass來寫的,只要選擇器滿足框架的要求即可。由于時間原因,就沒有在這個app里面去嘗試了。

4. 沒有雙向綁定。在vue里面,一個vue實例就是一個view-model;view層對數據的更新,會實時反饋到model;model的更新,也會實時反饋的到view。在小程序里面,沒有雙向綁定,view的更新不會直接同步到model;需要在相關事件回調里面,直接從view層拿到數據,然后通過setData的方式,更新model,小程序內部會在setData之后重新渲染page。比如單個todo項,toggle的操作:

toggleTodo: function( e ) { var id = this.getTodoId( e, 'todo-item-chk-' ); var value = e.detail.value[ 0 ]; var complete = !!value; var todo = this.getTodo( id ); todo.complete = complete; this.updateData( true ); this.updateStorage();},

以上代碼中,通過e.detail.value[0]拿到單個todo項里面checkbox的值,通過該值來判斷todo的complete狀態。最后在updateData的內部,還會通過setData方法,刷新model的內容。只有這樣,在toggle操作之后,app底部的統計信息才會更新。

5. 事件綁定的時候,無法傳遞參數,只能傳遞一個event。比如上面那個toggle的操作,我其實很想在回調里面把當前todo的id傳到這個回調里面,但是想盡辦法都做不到,最后只能通過id的方式來處理:就是在wxml中綁定事件的組件上面,加一個id,這個id全page也不能重復,所以id得加前綴,然后在id最后加上todo的id值;當事件觸發的時候,通過e.currentTarget.id就能拿到該組件的id,去掉相應的id前綴,就得到todo的id值了。這是目前用到的一個方法,我認為不是很優雅,希望后面能發現更好的辦法來實現。

6. app中考慮到了loading的效果,要利用button組件的loading屬性來實現。但是loading僅僅是一個樣式的控制,它不會控制這個按鈕是否能重復點擊。所以還要利用buttong的disabled屬性,防止重復點擊。

剩下的實現細節,都在下面兩個文件的源碼中,歡迎大家指出其中的問題。

index.wxml的源碼:

<!--list.wxml--><view class="container"> <view class="app-hd">  <view class="fx1">   <input class="new-todo-input" value="{{newTodoText}}" auto-focus bindinput="newTodoTextInput"/>   </view>  <button type="primary" size="mini" bindtap="addOne" loading="{{addOneLoading}}" disabled="{{addOneLoading}}">   + Add  </button> </view> <view class="todos-list" >  <view class="todo-item {{index == 0 ? '' : 'todo-item-not-first'}} {{todo.complete ? 'todo-item-complete' : ''}}" wx:for="{{todos}}" wx:for-item="todo">   <view wx-if="{{!todo.editing}}">    <checkbox-group id="todo-item-chk-{{todo.id}}" bindchange="toggleTodo">     <label class="checkbox">      <checkbox value="1" checked="{{todo.complete}}"/>     </label>    </checkbox-group>   </view>   <view id="todo-item-txt-{{todo.id}}" class="todo-text" wx-if="{{!todo.editing}}" bindlongtap="startEdit">    <text>{{todo.text}}</text>   </view>   <view wx-if="{{!todo.editing}}">    <button id="btn-del-item-{{todo.id}}" bindtap="clearSingle" type="warn" size="mini" loading="{{todo.loading}}" disabled="{{todo.loading}}">      Clear    </button>   </view>   <input id="todo-item-edit-{{todo.id}}" class="todo-text-input" value="{{todo.text}}" auto-focus bindblur="endEditTodo" wx-if="{{todo.editing}}"/>   </view> </view> <view class="app-ft" wx:if="{{todos.length > 0}}">  <view class="fx1">   <checkbox-group bindchange="toggleAll">    <label class="checkbox">     <checkbox value="1" checked="{{todosOfUncomplted.length == 0}}"/>    </label>   </checkbox-group>   <text>{{todosOfUncomplted.length}} left.</text>  </view>  <view wx:if="{{todosOfComplted.length > 0}}">   <button type="warn" size="mini" bindtap="clearAll" loading="{{clearAllLoading}}" disabled="{{clearAllLoading}}">     Clear {{todosOfComplted.length}} of done.   </button>  </view> </view> <loading hidden="{{loadingHidden}}" bindchange="loadingChange">  {{loadingText}} </loading> <toast hidden="{{toastHidden}}" bindchange="toastChange">  {{toastText}} </toast></view>

index.js的源碼:

var app = getApp();Page( { data: {  todos: [],  todosOfUncomplted: [],  todosOfComplted: [],  newTodoText: '',  addOneLoading: false,  loadingHidden: true,  loadingText: '',  toastHidden: true,  toastText: '',  clearAllLoading: false }, updateData: function( resetTodos ) {  var data = {};  if( resetTodos ) {   data.todos = this.data.todos;  }  data.todosOfUncomplted = this.data.todos.filter( function( t ) {   return !t.complete;  });  data.todosOfComplted = this.data.todos.filter( function( t ) {   return t.complete;  });  this.setData( data ); }, updateStorage: function() {  var storage = [];  this.data.todos.forEach( function( t ) {   storage.push( {    id: t.id,    text: t.text,    complete: t.complete   })  });  wx.setStorageSync( 'todos', storage ); }, onLoad: function() {  this.setData( {   todos: wx.getStorageSync( 'todos' ) || []  });  this.updateData( false ); }, getTodo: function( id ) {  return this.data.todos.filter( function( t ) {   return id == t.id;  })[ 0 ]; }, getTodoId: function( e, prefix ) {  return e.currentTarget.id.substring( prefix.length ); }, toggleTodo: function( e ) {  var id = this.getTodoId( e, 'todo-item-chk-' );  var value = e.detail.value[ 0 ];  var complete = !!value;  var todo = this.getTodo( id );  todo.complete = complete;  this.updateData( true );  this.updateStorage(); }, toggleAll: function( e ) {  var value = e.detail.value[ 0 ];  var complete = !!value;  this.data.todos.forEach( function( t ) {   t.complete = complete;  });  this.updateData( true );  this.updateStorage(); }, clearTodo: function( id ) {  var targetIndex;  this.data.todos.forEach( function( t, i ) {   if( targetIndex !== undefined ) return;   if( t.id == id ) {    targetIndex = i;   }  });  this.data.todos.splice( targetIndex, 1 ); }, clearSingle: function( e ) {  var id = this.getTodoId( e, 'btn-del-item-' );  var todo = this.getTodo( id );  todo.loading = true;  this.updateData( true );  var that = this;  setTimeout( function() {   that.clearTodo( id );   that.updateData( true );   that.updateStorage();  }, 500 ); }, clearAll: function() {  this.setData( {   clearAllLoading: true  });  var that = this;  setTimeout( function() {   that.data.todosOfComplted.forEach( function( t ) {    that.clearTodo( t.id );   });   that.setData( {    clearAllLoading: false   });   that.updateData( true );   that.updateStorage();   that.setData( {    toastHidden: false,    toastText: 'Success'   });  }, 500 ); }, startEdit: function( e ) {  var id = this.getTodoId( e, 'todo-item-txt-' );  var todo = this.getTodo( id );  todo.editing = true;  this.updateData( true );  this.updateStorage(); }, newTodoTextInput: function( e ) {  this.setData( {   newTodoText: e.detail.value  }); }, endEditTodo: function( e ) {  var id = this.getTodoId( e, 'todo-item-edit-' );  var todo = this.getTodo( id );  todo.editing = false;  todo.text = e.detail.value;  this.updateData( true );  this.updateStorage(); }, addOne: function( e ) {  if( !this.data.newTodoText ) return;  this.setData( {   addOneLoading: true  });  //open loading  this.setData( {   loadingHidden: false,   loadingText: 'Waiting...'  });  var that = this;  setTimeout( function() {   //close loading and toggle button loading status   that.setData( {    loadingHidden: true,    addOneLoading: false,    loadingText: ''   });   that.data.todos.push( {    id: app.getId(),    text: that.data.newTodoText,    compelte: false   });   that.setData( {    newTodoText: ''   });   that.updateData( true );   that.updateStorage();  }, 500 ); }, loadingChange: function() {  this.setData( {   loadingHidden: true,   loadingText: ''  }); }, toastChange: function() {  this.setData( {   toastHidden: true,   toastText: ''  }); }});

最后需要補充的是,這個app在有限的時間內依據微信的官方文檔進行開發,所以這里面的實現方式到底是不是合理的,我也不清楚。我也僅僅是通過這個app來了解小程序這個平臺的用法。希望微信官方能夠推出一些更全面、最好是項目性的demo,在代碼層面,給我們這些開發者提供一個最佳實踐規范。歡迎有其它的開發思路的朋友,幫我指出我以上實現中的問題。

通過此文,希望大家了解微信小程序的框架,謝謝大家對本站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久精品视频在线观看| 国产一区二区丝袜| 亚洲免费伊人电影在线观看av| 色老头一区二区三区| 久久午夜a级毛片| 欧美一性一乱一交一视频| 成人深夜直播免费观看| 日韩精品中文字幕有码专区| 成人有码在线视频| 国产日韩欧美成人| 国产精品三级美女白浆呻吟| 久久精品国产99国产精品澳门| 国产97在线播放| 日本一本a高清免费不卡| 日本午夜在线亚洲.国产| 中文字幕成人精品久久不卡| 国产亚洲欧洲高清一区| 欧美日韩国产黄| 欧美在线观看视频| 亚洲一区二区久久久| 国产精品久久久久久久久男| 精品激情国产视频| 国产精品久久久久久久美男| 成人精品久久久| 国产一区二区视频在线观看| 国产婷婷成人久久av免费高清| 91色琪琪电影亚洲精品久久| 精品视频在线播放| 精品国产鲁一鲁一区二区张丽| 亚洲性av网站| 日韩精品中文字幕视频在线| 国产欧美va欧美va香蕉在线| 精品精品国产国产自在线| 精品亚洲国产视频| 亚洲成人三级在线| 成人亚洲激情网| 红桃av永久久久| 欧美亚州一区二区三区| 91成人在线播放| 国产一区二区三区视频免费| 亚洲激情第一页| www.日韩av.com| 亚洲精品成人久久电影| 久久久久久欧美| 国内精品中文字幕| 97超碰色婷婷| 国产午夜精品久久久| 国产成人一区二区三区小说| 欧美日韩国产成人在线观看| 亚洲一区二区三区xxx视频| 美乳少妇欧美精品| 精品亚洲va在线va天堂资源站| 在线视频欧美性高潮| 亚洲一区亚洲二区亚洲三区| 国产噜噜噜噜噜久久久久久久久| 欧美日本亚洲视频| 91精品久久久久久久久久另类| 欧美性极品xxxx做受| 中文字幕精品www乱入免费视频| 精品久久久久国产| 欧美猛男性生活免费| 日韩经典中文字幕在线观看| 亚洲另类激情图| 亚洲一区二区久久| 搡老女人一区二区三区视频tv| 成人福利视频在线观看| 全球成人中文在线| 狠狠色噜噜狠狠狠狠97| 久久久久北条麻妃免费看| 国产精品96久久久久久| 国内成人精品一区| 欧美日韩在线观看视频小说| 亚洲精品第一国产综合精品| 久久精品国产69国产精品亚洲| 国产不卡一区二区在线播放| 操人视频在线观看欧美| 亚洲精品小视频| 国产精品久久久久久久久影视| 亚洲偷熟乱区亚洲香蕉av| 亚洲精品永久免费精品| 国产成人精品免高潮在线观看| 成人免费激情视频| 欧美黑人性猛交| 亚洲丝袜在线视频| 在线视频日韩精品| 免费av一区二区| 亚洲综合在线播放| 久久av.com| 精品国产一区二区三区久久狼5月| 日韩精品久久久久| 日韩成人免费视频| 69视频在线播放| 欧美巨乳在线观看| 免费99精品国产自在在线| 日韩欧美国产免费播放| 中文字幕久精品免费视频| 国产中文字幕日韩| 久久天堂电影网| 欧美成人黑人xx视频免费观看| 欧美精品一区三区| 欧美性生交xxxxx久久久| 热久久免费国产视频| 色综合影院在线| 91在线免费视频| 欧美激情手机在线视频| 成人免费视频97| 欧美激情中文字幕在线| 91天堂在线观看| 久久久久久久久网站| 欧美成人免费在线视频| 日韩高清av一区二区三区| 在线播放日韩精品| 国产精品一香蕉国产线看观看| 国产精品一区二区三区久久久| 亚洲国内精品在线| 欧美亚洲视频一区二区| 国产成人一区二区三区| 青青草原一区二区| 国产精品一区av| 久久久av免费| 欧美成人在线网站| 中文字幕精品一区二区精品| 97视频在线观看网址| 亚洲aa中文字幕| 欧美xxxx做受欧美.88| 91精品久久久久久久久久久久久| 日韩免费观看在线观看| 欧美国产日本高清在线| 欧美日韩国产色视频| 视频在线观看99| 中文字幕v亚洲ⅴv天堂| 高清欧美性猛交xxxx黑人猛交| 九九热视频这里只有精品| 亚洲成人免费网站| 日韩最新中文字幕电影免费看| 欧美精品videos| 亚洲视屏在线播放| 伊人久久久久久久久久久| 久久久久久网址| 色www亚洲国产张柏芝| 国产福利精品av综合导导航| 97国产一区二区精品久久呦| 国产精品6699| 亚洲free性xxxx护士hd| 亚洲精品美女免费| 欧美亚洲国产日韩2020| 国产精品极品尤物在线观看| 成人国产精品一区二区| 国产成人自拍视频在线观看| 色综合色综合网色综合| 欧美床上激情在线观看| 91久久精品国产91久久| 2019亚洲日韩新视频| 97超级碰碰碰久久久| 亚洲欧美国产高清va在线播| 成人免费大片黄在线播放| 国产精品高潮呻吟久久av黑人| 国产精品老女人精品视频| 97色在线视频| 操人视频在线观看欧美| 国产日韩欧美在线观看| 91系列在线播放| 国产精品久久综合av爱欲tv| 国产v综合ⅴ日韩v欧美大片|