學習小程序從「你」開始

最近的十幾天中在接觸小程序,從看別人的開源項目,到如今本身作一個項目,整個過程當中心情是有起有落,也學到了不少東西,接下來和你們一塊兒分享本身的學習過程,一塊兒交流,一塊兒學習:javascript

選題

在作項目的開始,咱們首先要作的事就是選擇主題了,不管咱們是選擇仿一個項目,仍是選擇本身原創一個項目,都要面對選擇主題,對不一樣層次的學習者來講,主題的選擇的思考不一樣。對於本身來講,仍是一個初入小程序的新人,我就說說我本身如今對選題的見解,做爲一個新手,我更多的是偏向選擇一個本身感受容易上手的項目,例如先仿一個開源項目,熟悉小程序的一些組件、API等,也就是熟悉小程序的一些開發套路,不要爲了作項目而去作項目,要清楚作項目的目的是什麼,是學習,仍是 完成老闆任務,仍是爲了更多的star等等,這個得本身去思考。css

說了這麼多還沒說本身作了什麼,我作的是仿知乎,目的在於想經過此次學習對小程序有一個更好的認識,此次的學習也是在前輩的鋪墊下進一步的學習,學習到了不少前輩的想法,感受很不錯。下面我和你們分享整個項目編寫過程個人一些思考,遇到的問題和見解等等。html

項目已實現功能:

  • 列表式渲染數據
  • 上拉刷新
  • 下拉加載更多
  • 頁面跳轉
  • 傳參頁面跳轉
  • 按鈕點擊彈窗
  • 圖片輪播
  • 頂部導航等等

項目效果:

  • 底部tabBar切換

圖片描述

  • 首頁切換

圖片描述

  • 上拉刷新下拉加載

圖片描述

  • 點擊事件及頁面跳轉

圖片描述

  • 評論功能

圖片描述

上面是目前項目已經實現的部分,其餘功能在往後會繼續實現。前端

項目的初心

在整個項目開始以前,我思考過這個問題,我寫這個項目是爲何,這是本身寫項目的動力,本身如今還處於學習階段,更多的是想經過這個項目本身可以學到什麼,編程技巧,編程思想,對小程序的熟悉程度等等,因此本身在寫代碼的時候多去用用以前本身沒有接觸過的東西,例如commonJS中的文件引入的方法同時也使用了ES6中模塊化引入的方法等等,不少人可能不理解爲何要這麼用,明明能夠那樣作。對於一個學習者來講,要儘量的在一個項目中多用到不一樣的方法,讓本身知道有這麼個東西的存在並學會掌握方便往後的項目中的使用,這才實現了作這個項目的價值。即對如今的我來講,仿知乎這個項目的初心是爲了學習更多本身沒有接觸到的東西,讓本身對編程有進一步的瞭解。java

項目介紹

  • 項目起步

項目開始的時候我首先思考的問題就是文件排版,一個完整的項目應該對文件有一個合理的結構,須要模塊化,加強項目的可讀性,操做和之後維護起來也就更加的方便了。看看本身的文件的目錄:
圖片描述圖片描述圖片描述圖片描述圖片描述圖片描述node

上面就是本身項目的主要目錄了,按照本身的想法對其分解,可是仍是存在着不少的問題,編寫的並非很好,不少的功能的實現代碼沒有單獨的用不一樣的文件區分開,都是在一個文件中編寫,這須要進一步的優化,模塊化在編程中是一個挺重要的思想,能夠很好的實現代碼的重用性,能夠節約必定的開發時間。最近也在看看前端工做流的一些東西,項目目錄也是分爲開發目錄和上線目錄,能夠經過babel、gulp、webpack等對開發文件的一些處理,也是挺不錯的一種思想,對這瞭解的還不是不少,還在學習中,之後項目開發中能夠用,增長本身對企業級開發的實踐,這也是你們能夠學習的一個方向。webpack

  • 後臺數據方面

開發項目中不可缺乏的就是數據了,如今的項目中的頁面再也不多是靜態頁面了,把數據給寫si了,這沒有任何價值,同時也增長了編程的工做量,代碼也很冗長。這就須要模擬後臺數據,能夠實現列表式渲染數據,減小了不少的工做量,這就出現了一個問題,怎麼模擬後臺數據,用什麼去模仿數據,不少人會用第三方提供的,例如使用easy-mock,經過wx.request()來獲取數據,實現頁面加載數據,相信這種方式你們都會用。若是在本地寫假數據,那咱們又該用什麼寫,怎樣獲取數據,對一個初學者來講應該是不太清楚的(大佬除外),這個就是咱們能夠學習的地方,學會用不同的方式去作一件事,這就會實現作這個項目的目的。css3

說到這裏,數據應該是放在js文件中,通常後臺數據都是JSON格式,因此放在js文件最爲合理了,這時問題又出現了,咱們怎麼獲取裏面的數據呢?想到這個我也不曉得怎麼獲取裏面的數據,看到前輩有用到require()的方式獲取數據,想一想這個是什麼東西,開發經驗不足,不曉得這個是什麼東西,本身就會主動的去了解這個是什麼東西,原來這個是node中CommonJS中的模塊實現,js以前並無很好的實現模塊化編程,幾乎全部的代碼都寫在一個文件中,CommonJS的出現,實現了JS的模塊化,同時本身也曉得了ES6中也有了屬於本身模塊化的方式了,使用import、export方式實現模塊化編程,感受本身又學到了,在本身的項目中就都有用到這兩種方式來獲取數據:git

圖片描述圖片描述圖片描述圖片描述圖片描述

看上面的圖片,就能夠看到我兩種方式在一個項目中都是有使用到的,你可能沒有看懂下哦貼出來的是什麼,你不須要看懂,如今快去看看CommonJS和ES6中模塊化的知識,你又會學到東西的!!!有人就會不理解,幹嗎要在本地寫假數據啊,這不在佔存儲量嗎,爲何要用兩種模塊化的方式啊,一種不就好了嗎等等問題,其實我作的不是「項目」,我更多的是想經過這個項目我能學到什麼東西,這裏我知道了兩種模塊化的方式,而後我能夠在後面多花點時間對着兩種模塊化方式深刻學習,這個就是我想要的結果,真正的項目開發中就不要把假數據放在本地,也不要一件事情同時使用兩種方式去作,如今能夠玩玩,哈哈哈哈哈哈哈!!!!!es6

  • 引用第三方框架問題

不少人確定也思考過作項目是否使用第三方框架,仍是本身寫原生代碼,這個問題就要看本身的想法了,我就說說我本身的見解,我如今接觸前端的時間不長,不少的東西都不是很清楚,像wxss的樣式想本身去寫,多熟悉樣式屬性,其實讓我用第三方的框架我也不是很會用,可是仍是要多去用,要「會」用框架。在這個項目中大部分的wxss文件都是本身寫的,到了後面有的功能的樣式,我也用了第三方框架,像小程序中經常使用的UI框架中有weui,這個很好用,微信團隊開發的一個框架,提供了不少的組件,能夠減小不少的開發時間。

個人態度是,若是是學習的態度那就本身寫原生代碼這樣提高我認爲是比較快的,若是是實際開發項目,那就是能用框架那就用框架,不要本身造輪子。

  • 項目主要功能實現過程當中的思考

小程序開發模式和咱們傳統的開發模式很不相同,傳統的開發中咱們通常是使用dom操做來動態的改變頁面,讓我感受的是一種查找的方式,使用dom操做,找到某個元素而後再改變該元素的行爲,從而改變了頁面的狀態,而小程序的開發模式是MVVM,數據綁定頁面,數據的改變從而使得頁面狀態發生改變,這個傳統的開發很不相同,這個在小程序開發很容易踩坑,本身在這個項目中就踩到過這個坑,要理解好MVVM模式。

1.按鈕點擊彈窗事件

<block wx:for="{{feed}}" wx:for-index="idx" wx:for-item="item" wx:key="idx" data-idx="{{idx}}" >
  <view  class="feed-item">      
     <view class="feed-source">
       <!--遮罩層-->
       <view class="drawer_screen" bindtap="hide" data-statu="close" wx:if="{{showModalStatus}}"></view>
       <!--彈窗事件觸發-->
       <view bindtap="powerDrawer" data-statu="open" data-answerId="{{item.answer_id}}">
           <image class="item-more" mode="aspectFit" src="../../images/more.png"></image>
       </view>
     </view>
     <!--彈窗頁面-->
     <view animation="{{animationData}}" data-answerId="{{item.answer_id}}" class="drawer_box" wx:if="{{showModalStatus&&item.isSelected}}">
        <view class="drawer_shield">屏蔽這個問題</view>
        <view class="drawe_report">舉報</view>
     </view>
  </view>
</block>
var util = require('../../utils/util.js');const app = getApp();
Page({ 
    // 頁面初始數據
    data: {
    //  數據源feed: [],
    //  更多按鈕 觸發彈窗
    showModalStatus: false ,
    },
    // 彈窗觸發事件
    powerDrawer: function (e) { 
      // 獲取數據源
      let feed = this.data.feed;
    // 獲得按鈕點擊時設置的數據值 
        data-answerId
        let answer_id = e.currentTarget.dataset.answerid;
        // 獲得按鈕點擊時設置的數據值 data-statu
        let currentStatu = e.currentTarget.dataset.statu;
        // 遍歷數據源
        for(let key of feed)
        {
           if(key.answer_id === answer_id){      
               key.isSelected = true;
            }
        }
        this.setData({
           feed:feed,
        });
        // 彈出窗
        this.util(currentStatu);}
    })
//數據源模板
var next = {
  "data": [
        {
          "topic": "教育",         
          "answer_id": 1,
          ...
        },
        {
           "topic": "教育",
           "answer_id": 2,
           ...
        },
        {
           ...
        },
        ...
    ]
}

上面就是點擊按鈕彈窗事件的主要代碼,由於作的是列表式數據渲染,基本頁面的佈局只寫了一個,經過js中的數據綁定,能夠將數據源中的全部的數據均可以導入頁面中,這樣能夠減小不少的工做量。如今就和你們分享我在寫這個觸發事件遇到的問題,你們看下面的圖就清楚問題在哪裏了:

圖片描述

看到圖就曉得了問題來了,單獨點擊一個,其餘框也觸發了彈窗事件,這是作列表式渲染數據都容易遇到的問題,遇到的坑,爲何會出現這種問題呢,緣由很簡單,由於在寫頁面佈局的時候,咱們是經過<block wx:for=""></block>動態填充數據的,基本的樣式只寫了一個,每個數據都有bindtap觸發事件

圖片描述

起初遇到這個問題,我想的辦法是,數據源中的數據是寫在數組中,每一數據都有本身固定的"answer_id" ,而後我在觸發彈窗時填入一個數據data-answerId="{{item.answer_id}}",設置的值也爲answer_id,我就想經過查找的方式,找到每個數據的answer_id再和觸發按鈕時的設置的數據進行對比,若是值同樣,就彈出其自身的窗,然而並無解決問題,下面是最初設計的代碼:

圖片描述

這就是想經過查找的方式來解決問題,沒有作到,緣由是你每次查找的值和你觸發時設置的值都是同樣的,因此是解決不了問題的,這種作法就還停留在傳統的開發設計,如dom操做,不斷的查找,找到某個值,而後再改變它。單純的使用這種作法在小程序有些難度來解決問題了,其實要正確的理解MVVM模式,這個問題就很好解決了,數據綁定頁面,數據改版頁面的狀態。

解決這個問題的方法就是爲每個數據添加一個布爾值,觸發自身的按鈕事件時其布爾值爲true,其餘的數據的布爾值爲false

圖片描述圖片描述

這樣的寫法就很好的解決了問題,查找操做和數據綁定操做一塊兒解決問題。

2.評論功能

<view class="comment-bd">
   <view class="ordinaryComment">
       <text>評論</text>
    </view>
    <block wx:for="{{item.ordinaryComment}}" wx:key="index">
        <view class="user-comment">
           <view class="user-avatar">
             <image src="{{item.feed_source_img}}"></image>
           </view>
            <view class="comment-content">
               <view class="user-name">
                    <text>{{item.feed_source_name}}</text>
               </view>
               <view class="answer-content">
                    <text>{{item.content}}</text>
               </view>
               <view class="comment-action">
               <view class="like dot">
                    <text>點贊 {{item.good_num}}</text>
                </view>
               <view class="comment dot">
                     <text>回覆{{item.comment_num}}</text>
               </view>
               <view class="time">
                      <text>{{item.time}}</text>
                </view>
          </view>
      </view>
     </view>
   </block>
  </view>
 <view class="comment-ft">
     <view class="commentInput">
        <input type="text" value="{{content}}" bindinput="onTextChanged" placeholder="請輸入評論" placeholder-class="placeholderClass" />
     </view>
      <view class="commentBtn">
          <text bindtap="onSendClicked" data-questionId="{{item.question_id}}">發佈</text>
       </view>
</view>
var util = require('../../utils/util.js');
let myComment = '';
Page({
   data: {     
        comment: [],    
        content: "", 
        },
    onTextChanged: function(e){
     //獲取文本框的值,即輸入的評論的內容
      myComment = e.detail.value; 
     },
    onSendClicked: function(e){
        //獲取觸發時設置數據的值
        let question_id = e.target.dataset.questionid;
        var that = this,conArr = [];
        //定時器,100ms後觸發
        setTimeout(function(){
            //將評論的基本信息存入數組
             if(myComment.length > 0){
                 conArr.push({     
                 "feed_source_img": "../../images/icon9.jpeg",     
                 "feed_source_name": "zero",     
                 "time": util.formatTime(new Date()),     
                 "good_num": "0",    
                  "comment_num": "0",     
                  "content": myComment     
      })
        //從數據源中獲取評論頁面的全部數據
        var feed = util.getData2();
        let comment_data = feed.comment;
        //找到指定頁面的評論數據
        const comment = comment_data.filter((comment) => {
           return question_id == comment.question_id;})
            //將添加的評論的基本信息數組conArr合併到數據源中評論數據的數組comment[0].ordinaryComment中
            var commentContent = comment[0].ordinaryComment.concat(conArr);
            //將新加入的conArr數組放在源數組中的第一位,便於觸發提交評論時評論內容出如今頁面的第一欄
            var newCommentContent = commentContent.reverse();
            var newComment = comment[0];
            comment[0].ordinaryComment = newCommentContent;
            that.setData({
                comment: comment,
                content: ""
            })
        }
       },100)
    },
})

上面就是評論功能的主要代碼,要實現這個功能主要解決的問題是找到指定問題的評論頁面,經過Array.filter()方法能夠找到指定問題的評論頁面,而後又解決的問題是將填寫的評論信息加到數據源中評論數據的數組comment[0].ordinaryComment中,經過Array.concat()方法能夠實現,最後就是將新的數據展現到頁面上,更新頁面狀態,其中還有一個地方主要注意:如何將輸入的評論信息,顯示在評論欄的第一欄,Array.reverse()能夠解決這個問題,這樣就比較好的實現了這個功能。

3.其餘功能總結
像比較常見的功能還有首頁頂部的tab切換,可使用swiper-item組件和bindtap進行事件綁定,能夠實現這種tab切換的效果,下拉刷新的可使用scroll-view組件,組件裏面提供了不少的屬性能夠實現不少的功能,還有基本的彈窗功能的組件有wx.showToast()、wx.showActionSheet(OBJECT)、wx.showModal(OBJECT)等等,這些組件均可以看官方文檔學習,學習利用基本組件。

相關文檔和工具

  1. 小程序開發文檔 學會使用開發文檔,多看開發文檔,熟悉組件,避免本身沒必要要的麻煩提供
  2. commonJS學習 比較強的模塊化的學習
  3. ES6模塊化 屬於本身的模塊化開發
  4. iconfont @font-face 學會使用CSS3 font-size屬性 頁面圖片再也不是png格式了,值得學習
  5. weui 學會使用第三方框架,小程序須要學習weui
  6. 小程序開發者工具 小程序開發工具

結束

此次的學習學到了挺多東西的,要想清除作這個項目的目的是什麼,這個項目個人目的就是爲了學習,曉得了本身缺乏什麼,什麼須要去增強學習的,在整個項目的完成過程當中,其實感受到了本身的功利心,但願本身快點把項目作完,這個在學習的過程當中是很很差的,忘記了本身作項目的初心,做爲一個學習者,咱們應該多想一想作這個項目能給本身帶來什麼,我能夠經過行動具體的給本身帶來哪些幫助,咱們應該要實現這個項目對本身的最大效益,這纔是這個項目的存在價值,要對得起這個項目,不要僅僅趨於我作了這個項目,作好了,我無論了,須要不忘初心的學習,作一個有思想的程序猿!!!!!

最後附上這個項目的github地址和我的的聯繫方式,咱們能夠一塊兒交流學習,共同進步
項目地址:https://github.com/DengSongso...
我的郵箱:DengSongsong1010@163.com
wx: dss1000010
若是以爲這篇文章和項目有好處,歡迎star哦,謝謝你們!!!

相關文章
相關標籤/搜索