首頁 微信小程式 小程式開發 關於微信小程式中框架的解析

關於微信小程式中框架的解析

Jun 27, 2018 pm 02:39 PM
微信小程式 框架

這篇文章主要介紹了微信小程式框架詳解及實例應用的相關資料,需要的朋友可以參考下

快速了解微信小程式的使用,一個根據小程式的框架開發的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 ? &#39;&#39; : &#39;todo-item-not-first&#39;}} {{todo.complete ? &#39;todo-item-complete&#39; : &#39;&#39;}}" 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: &#39;&#39;,
  addOneLoading: false,
  loadingHidden: true,
  loadingText: &#39;&#39;,
  toastHidden: true,
  toastText: &#39;&#39;,
  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( &#39;todos&#39;, storage );
 },
 onLoad: function() {
  this.setData( {
   todos: wx.getStorageSync( &#39;todos&#39; ) || []
  });
  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, &#39;todo-item-chk-&#39; );
  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, &#39;btn-del-item-&#39; );
  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: &#39;Success&#39;
   });
  }, 500 );

 },
 startEdit: function( e ) {
  var id = this.getTodoId( e, &#39;todo-item-txt-&#39; );
  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, &#39;todo-item-edit-&#39; );
  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: &#39;Waiting...&#39;
  });

  var that = this;
  setTimeout( function() {
   //close loading and toggle button loading status
   that.setData( {
    loadingHidden: true,
    addOneLoading: false,
    loadingText: &#39;&#39;
   });

   that.data.todos.push( {
    id: app.getId(),
    text: that.data.newTodoText,
    compelte: false
   });

   that.setData( {
    newTodoText: &#39;&#39;
   });

   that.updateData( true );
   that.updateStorage();
  }, 500 );
 },
 loadingChange: function() {
  this.setData( {
   loadingHidden: true,
   loadingText: &#39;&#39;
  });
 },
 toastChange: function() {
  this.setData( {
   toastHidden: true,
   toastText: &#39;&#39;
  });
 }
});
登入後複製

最后需要补充的是,这个app在有限的时间内依据微信的官方文档进行开发,所以这里面的实现方式到底是不是合理的,我也不清楚。我也仅仅是通过这个app来了解小程序这个平台的用法。希望微信官方能够推出一些更全面、最好是项目性的demo,在代码层面,给我们这些开发者提供一个最佳实践规范。欢迎有其它的开发思路的朋友,帮我指出我以上实现中的问题。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

关于微信小程序解析网页内容的介绍

关于微信小程序的动态传参

关于微信JS-SDK选取手机照片上传的功能

以上是關於微信小程式中框架的解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1318
25
PHP教程
1269
29
C# 教程
1248
24
如何評估Java框架商業支援的性價比 如何評估Java框架商業支援的性價比 Jun 05, 2024 pm 05:25 PM

評估Java框架商業支援的性價比涉及以下步驟:確定所需的保障等級和服務等級協定(SLA)保證。研究支持團隊的經驗和專業知識。考慮附加服務,如昇級、故障排除和效能最佳化。權衡商業支援成本與風險緩解和提高效率。

PHP 框架的學習曲線與其他語言框架相比如何? PHP 框架的學習曲線與其他語言框架相比如何? Jun 06, 2024 pm 12:41 PM

PHP框架的學習曲線取決於語言熟練度、框架複雜性、文件品質和社群支援。與Python框架相比,PHP框架的學習曲線較高,而與Ruby框架相比,則較低。與Java框架相比,PHP框架的學習曲線中等,但入門時間較短。

Java框架的效能比較 Java框架的效能比較 Jun 04, 2024 pm 03:56 PM

根據基準測試,對於小型、高效能應用程序,Quarkus(快速啟動、低記憶體)或Micronaut(TechEmpower優異)是理想選擇。 SpringBoot適用於大型、全端應用程序,但啟動時間和記憶體佔用稍慢。

PHP 框架的輕量級選項如何影響應用程式效能? PHP 框架的輕量級選項如何影響應用程式效能? Jun 06, 2024 am 10:53 AM

輕量級PHP框架透過小體積和低資源消耗提升應用程式效能。其特點包括:體積小,啟動快,記憶體佔用低提升響應速度和吞吐量,降低資源消耗實戰案例:SlimFramework創建RESTAPI,僅500KB,高響應性、高吞吐量

golang框架文件最佳實踐 golang框架文件最佳實踐 Jun 04, 2024 pm 05:00 PM

編寫清晰全面的文件對於Golang框架至關重要。最佳實踐包括:遵循既定文件風格,例如Google的Go程式設計風格指南。使用清晰的組織結構,包括標題、子標題和列表,並提供導覽。提供全面且準確的信息,包括入門指南、API參考和概念。使用程式碼範例說明概念和使用方法。保持文件更新,追蹤變更並記錄新功能。提供支援和社群資源,例如GitHub問題和論壇。建立實際案例,如API文件。

如何為不同的應用場景選擇最佳的golang框架 如何為不同的應用場景選擇最佳的golang框架 Jun 05, 2024 pm 04:05 PM

根據應用場景選擇最佳Go框架:考慮應用類型、語言特性、效能需求、生態系統。常見Go框架:Gin(Web應用)、Echo(Web服務)、Fiber(高吞吐量)、gorm(ORM)、fasthttp(速度)。實戰案例:建構RESTAPI(Fiber),與資料庫互動(gorm)。選擇框架:效能關鍵選fasthttp,靈活Web應用選Gin/Echo,資料庫互動選gorm。

Java框架學習路線圖:不同領域中的最佳實踐 Java框架學習路線圖:不同領域中的最佳實踐 Jun 05, 2024 pm 08:53 PM

針對不同領域的Java框架學習路線圖:Web開發:SpringBoot和PlayFramework。持久層:Hibernate和JPA。服務端響應式程式設計:ReactorCore和SpringWebFlux。即時計算:ApacheStorm和ApacheSpark。雲端運算:AWSSDKforJava和GoogleCloudJava。

Golang框架學習過程中常見的迷思有哪些? Golang框架學習過程中常見的迷思有哪些? Jun 05, 2024 pm 09:59 PM

Go框架學習的迷思有以下5種:過度依賴框架,限制彈性。不遵循框架約定,程式碼難以維護。使用過時庫,帶來安全和相容性問題。過度使用包,混淆程式碼結構。忽視錯誤處理,導致意外行為和崩潰。

See all articles