1. 程式人生 > >微信小程式日記——高仿知乎日報(上)

微信小程式日記——高仿知乎日報(上)

該小程式的作者是Oopsguy,我也參與小功能的開發和完善,希望大家能支援一下

本人對知乎日報是情有獨鍾,看我的部落格和github就知道了,寫了幾個不同技術型別的知乎日報APP

要做微信小程式首先要對htmlcssjs有一定的基礎,還有對微信小程式的API也要非常熟悉

我將該教程分為以下三篇

三篇分別講不同的元件和功能塊

這篇要講

  • API分析
  • 啟動頁
  • 輪播圖
  • 日報列表
  • 浮動按鈕
  • 側滑選單

API分析

以下是使用到的具體API,更加詳細引數和返回結構可參照網上網友分享的 知乎日報-API-分析 ,在此就不做再次分析了。

啟動介面圖片

http://news-at.zhihu.com/api/4/start-image/{size}

引數 說明
size 圖片尺寸,格式:寬*高。例如: 768*1024

獲取剛進入應用時的顯示封面,可以根據傳遞的尺寸引數來獲取適配使用者螢幕的封面。

獲取最新日報

http://news-at.zhihu.com/api/4/news/latest

返回的資料用於日報的首頁列表,首頁的結構有上下部分,上部分是圖片滑動模組,用於展示熱門日報,下部分是首頁日報列表,以上介面返回的資料有熱門日報和首頁日報

獲取日報詳細

http://news-at.zhihu.com/api/4/news/{id}

引數 說明
id 日報id

在點選日報列表也的日報項時,需要跳轉到日報詳情頁展示日報的具體資訊,這個介面用來獲取日報的展示封面和具體內容。

歷史日報

http://news.at.zhihu.com/api/4/news/before/{date}

引數 說明
date 年月日格式時間yyyyMMdd,例如:20150903、20161202

這個介面也是用與首頁列表的日報展示,但是不同的是此介面需要傳一個日期引數,如20150804格式。獲取最新日報介面只能獲取當天的日報列表,如果需要獲取前天或者更久之前的日報,則需要這個介面單獨獲取。

日報額外資訊

http://news-at.zhihu.com/api/4/story-extra/{id}

引數 說明
id 日報id

在日報詳情頁面中,不僅要展示日報的內容,好需要額外獲取此日報的評論數目和推薦人數等額外資訊。

日報長評

http://news-at.zhihu.com/api/4/story/{id}/long-comments

引數 說明
id 日報id

日報的評論頁面展示長評用到的介面(沒有找到分頁引數,分頁沒有做)

日報短評

http://news-at.zhihu.com/api/4/story/{id}/short-comments

引數 說明
id 日報id

日報的評論頁面展示段評用到的介面(沒有找到分頁引數,分頁沒有做)

主題日報欄目列表

http://news-at.zhihu.com/api/4/themes

主頁的側邊欄顯示有主題日報的列表,需要通過這個介面獲取主題日報欄目列表

主題日報具體內容列表

http://news-at.zhihu.com/api/4/theme/{themeId}

引數 說明
themeId 主題日報欄目id

在主頁側欄點選主題日報進入主題日報的內容頁,需要展示此主題日報下的日報列表。

啟動頁

作為一個仿製知乎日報的偽APP,高大上的啟動封面是必須的,哈哈。啟動頁面很簡單,請求一個應用啟動封面介面,獲取封面路徑和版權資訊。當進入頁面,在onLoad事件中獲取螢幕的寬和高來請求適合尺寸的圖片,在onReady中請求載入圖片,在請求成果之後,延遲2s進入首頁,防止頁面一閃而過。

onLoad: function( options ) {
    var _this = this;
    wx.getSystemInfo( {
      success: function( res ) {
        _this.setData( {
          screenHeight: res.windowHeight,
          screenWidth: res.windowWidth,
        });
      }
    });
},

onReady: function() {
    var _this = this;
    var size = this.data.screenWidth + '*' + this.data.screenHeight;
    requests.getSplashCover( size, ( data ) => {
      _this.setData( { splash: data });
    }, null, () => {
      toIndexPage.call(_this);
    });
}

/**
 * 跳轉到首頁
 */
function toIndexPage() {
  setTimeout( function() {
    wx.redirectTo( {
      url: '../index/index'
    });
  }, 2000 );
}

Splash啟動頁面

輪播圖

首頁頂部需要用到輪播圖來展示熱門日報,小程式中的Swipe元件可以實現。

<swiper class="index-swiper" indicator-dots="true" interval="10000">
    <block wx:for="{{sliderData}}">
        <swiper-item data-id="{{item.id}}" bindtap="toDetailPage">
            <image mode="aspectFill" src="{{item.image}}" style="width:100%" />
            <view class="mask"></view>
            <view class="desc"><text>{{item.title}}</text></view>
        </swiper-item>
    </block>
</swiper>

所有的內容都必須要在swiper-item標籤中,因為我們的圖片不止有一張,而是有多個熱門日報資訊,需要用迴圈來展示資料。這裡需要指定的是image裡的屬性mode設定為aspectFill是為了適應元件的寬度,這需要犧牲他的高度,即有可能裁剪,但這是最好的展示效果。toDetailPage是點選事件,觸發跳轉到日報詳情頁。在跳轉到日報詳情頁需要附帶日報的id過去,我們在迴圈列表的時候把當前日報的id存到標籤的data中,用data-id標識,這有點類似與html5中的data-*API。當在這個標籤上發生點選事件的時候,我們可以通過Event.currentTarget.dataset.id來獲取data-id的值。

首頁

日報列表

列表的佈局大同小異,不過這裡的列表涉及到分頁,我們可以毫不猶豫地使用scroll-view元件,它的scrolltolower是非常好用的,當元件滾動到底部就會觸發這個事件。上次的小豆瓣圖書也是使用了這個元件分頁。不過這次的分頁動畫跟上次不一樣,而是用一個附帶旋轉動畫的重新整理圖示,使用官方的動畫api來實現旋轉。

<view class="refresh-block" wx:if="{{loadingMore}}">
    <image animation="{{refreshAnimation}}" src="../../images/refresh.png"></image>
</view>

程式碼中有一個顯眼的animation屬性,這個屬性就是用來控制動畫的。

/**
 * 旋轉上拉載入圖示
 */
function updateRefreshIcon() {
  var deg = 360;
  var _this = this;

  var animation = wx.createAnimation( {
    duration: 1000
  });

  var timer = setInterval( function() {
    if( !_this.data.loadingMore )
      clearInterval( timer );
    animation.rotateZ( deg ).step();
    deg += 360;
    _this.setData( {
      refreshAnimation: animation.export()
    })
  }, 1000 );
}

當列表載入資料時,給動畫設定一個時長duration,然後按Z軸旋轉,即垂直方向旋轉rotateZ,每次旋轉360度,週期是1000毫秒。

列表的佈局跟上次的小豆瓣圖書的結構差不多,用到了迴圈結構wx:for和判斷語句wx:ifwx:else來控制不同的展示方向。

<view class="common-list">
    <block wx:for="{{pageData}}">
        <view class="list-item {{item.images[0] ? 'has-img': ''}}" wx:if="{{item.type != 3}}" data-id="{{item.id}}" bindtap="toDetailPage">
            <view class="content">
                <text>{{item.title}}</text>
            </view>
            <image wx:if="{{item.images[0]}}" src="{{item.images[0]}}" class="cover"></image>
        </view>
        <view class="list-spliter" wx:else>
            <text>{{item.title}}</text>
        </view>
    </block>
</view>

class="list-spliter"這塊是用來顯示日期,列表中的日報只要不是同一天的記錄,就在中間插入一條日期顯示塊。在列表項中有一個三元運算判斷輸出具體的class{{item.images[0] ? 'has-img': ''}},是因為列表中可能沒有圖片,因此需要判定當前有沒有圖片,沒有圖片就不新增class為has-img來控制帶有圖片列表項的佈局。

浮動按鈕

因為小程式中沒有側欄元件,無法做到側滑手勢顯示側欄(本人發現touchstart事件和tap事件有衝突,無法實現出手勢側滑判斷,所以沒有用側滑手勢,可能是本人理解太淺了,沒有發現解決方法,嘿嘿…),浮動按鈕的樣式參照了Android中的FloatAction經典按鈕。可以浮動在介面上,還可以滑動到任意位置,背景為稍微透明。

<view class="float-action" bindtap="ballClickEvent" style="opacity: {{ballOpacity}};bottom:{{ballBottom}}px;right:{{ballRight}}px;" bindtouchmove="ballMoveEvent"> 
</view>
.float-action {
  position: absolute;
  bottom: 20px;
  right: 30px;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  box-shadow: 2px 2px 10px #AAA;
  background: #1891D4;
  z-index: 100;
}

按鈕的樣式隨便弄了一下,寬高用了px是因為後面的移動判斷需要獲取螢幕的寬高資訊,這些資訊的單位是px。wxml綁定了點選事件和移動事件,點選事件是控制側欄彈出,滑動事件是按鈕移動。

//浮動球移動事件
ballMoveEvent: function( e ) {
    var touchs = e.touches[ 0 ];
    var pageX = touchs.pageX;
    var pageY = touchs.pageY;
    if( pageX < 25 ) return;
    if( pageX > this.data.screenWidth - 25 ) return;
    if( this.data.screenHeight - pageY <= 25 ) return;
    if( pageY <= 25 ) return;
    var x = this.data.screenWidth - pageX - 25;
    var y = this.data.screenHeight - pageY - 25;
    this.setData( {
        ballBottom: y,
        ballRight: x
    });
}

touchmove事件中的會傳遞一個event引數,通過這個引數可以獲取到當前手勢滑動到的具體座標資訊e.touches[ 0 ]

側滑選單

側滑選單是一個經典APP佈局方案,小程式中沒有提供這個元件,甚是遺憾。不過實現起來也不是很難,但是總感覺有點彆扭…

側滑選單的樣式採用了固定定位的佈局position: fixed,預設隱藏與左側,當點選浮動按鈕時彈出,點選遮罩或者側欄上邊的關閉按鈕時收回。側欄的彈出和收回動畫採用小程式提供的動畫API。

<view class="slide-mask" style="display:{{maskDisplay}}" bindtap="slideCloseEvent"></view>
<view class="slide-menu" style="right: {{slideRight}}px;width: {{slideWidth}}px;height:{{slideHeight}}px;" animation="{{slideAnimation}}">
  <icon type="cancel" size="30" class="close-btn" color="#FFF" bindtap="slideCloseEvent" />
  <scroll-view scroll-y="true" style="height:100%;width:100%">
    <view class="header">
      <view class="userinfo">
        <image src="../../images/avatar.png" class="avatar"></image>
        <text>Oopsguy</text>
      </view>
      <view class="toolbar">
        <view class="item">
          <image src="../../images/fav.png"></image>
          <text>收藏</text>
        </view>
        <view class="item" bindtap="toSettingPage">
          <image src="../../images/setting.png"></image>
          <text>設定</text>
        </view>
      </view>
    </view>
    <view class="menu-item home">
      <text>首頁</text>
    </view>
    <view class="slide-inner">
      <block wx:for="{{themeData}}">
        <view class="menu-item" data-id="{{item.id}}" bindtap="toThemePage">
          <text>{{item.name}}</text>
          <image src="../../images/plus.png"></image>
        </view>
      </block>
    </view>    
  </scroll-view>
</view>
/*slide-menu*/
.slide-mask {
  position: fixed;
  width: 100%;
  top: 0;
  left: 0;
  bottom: 0;
  background: rgba(0, 0, 0, .3);
  z-index: 800;
}
.slide-menu {
  position: fixed;
  top: 0;
  background: #FFF;
  z-index: 900;
}
/*.slide-menu .slide-inner {
  padding: 40rpx;
}*/
.slide-menu .header {
  background: #019DD6;
  height: 200rpx;
  color: #FFF;
  padding: 20rpx 40rpx 0 40rpx;
}

.userinfo {
  height: 80rpx;
  line-height: 80rpx;
  overflow: hidden;
}
.userinfo .avatar {
  width: 80rpx;
  height: 80rpx;
  border-radius: 50%;
  margin-right: 40rpx;
  float: left;
}
.userinfo text {
  float: left;
  font-size: 35rpx;
}
.toolbar {
  height: 100rpx;
  padding-top: 25rpx;
  line-height: 75rpx;
}
.toolbar .item {
  width: 50%;
  display: inline-block;
  overflow: hidden;
  text-align: center
}
.toolbar .item text {
  display: inline-block;
  font-size: 30rpx
}
.toolbar .item image {
  display: inline-block;
  position: relative;
  top: 10rpx;
  margin-right: 10rpx;
  height: 50rpx;
  width: 50rpx;
}

.slide-menu .menu-item {
  position: relative;
  height: 100rpx;
  line-height: 100rpx;
  padding: 0 40rpx;
  font-size: 35rpx;
}
.slide-menu .menu-item:active {
  background: #FAFAFA;
}
.slide-menu .menu-item image {
  position: absolute;
  top: 25rpx;
  right: 40rpx;
  width: 50rpx;
  height: 50rpx;
}
.slide-menu .home {
  color: #019DD6
}

.slide-menu .close-btn {
  position: absolute;
  top: 20rpx;
  right: 40rpx;
  z-index: 1000
}

以上是側欄的一個簡單的佈局和樣式,包含了側欄中的使用者資訊塊和主題日報列表。當然這些資訊是需要通過js的中網路請求來獲取的。側欄結構上邊有一個class為slide-mask的view,這是一個遮罩元素,當側欄彈出的時候,側欄後邊就有一層輕微透明的黑色遮罩。側欄的高度和寬度初始是不定的,需要在進入頁面的時候,馬上獲取裝置資訊來獲取螢幕的高度寬度調整側欄樣式。

//獲取裝置資訊,螢幕的高度寬度
onLoad: function() {
    var _this = this;
    wx.getSystemInfo( {
      success: function( res ) {
        _this.setData( {
          screenHeight: res.windowHeight,
          screenWidth: res.windowWidth,
          slideHeight: res.windowHeight,
          slideRight: res.windowWidth,
          slideWidth: res.windowWidth * 0.7
        });
      }
    });
}

寬度我取了螢幕寬度的70%,高度一致。側欄的彈出收回動畫使用內建動畫API

//側欄展開
function slideUp() {
  var animation = wx.createAnimation( {
    duration: 600
  });
  this.setData( { maskDisplay: 'block' });
  animation.translateX( '100%' ).step();
  this.setData( {
    slideAnimation: animation.export()
  });
}

//側欄關閉
function slideDown() {
  var animation = wx.createAnimation( {
    duration: 800
  });
  animation.translateX( '-100%' ).step();
  this.setData( {
    slideAnimation: animation.export()
  });
  this.setData( { maskDisplay: 'none' });
}

側欄彈出的時候,遮罩的css屬性display設定為block顯示,側欄通過css動畫transform來想右側移動了100%的寬度translateX(100%),側欄收回時,動畫恰好與彈出的相反,其實這些動畫最後都會翻譯為css3動畫屬性,這些API只是css3動畫的封裝。為了點選遮罩收回側欄,遮罩的tap事件也要繫結slideCloseEvent

//浮動球點選 側欄展開
ballClickEvent: function() {
    slideUp.call( this );
},

//遮罩點選  側欄關閉
slideCloseEvent: function() {
    slideDown.call( this );
}

效果圖

側欄選單

相關推薦

程式日記——仿日報

該小程式的作者是Oopsguy,我也參與小功能的開發和完善,希望大家能支援一下 本人對知乎日報是情有獨鍾,看我的部落格和github就知道了,寫了幾個不同技術型別的知乎日報APP 要做微信小程式首先要對html,css,js有一定的基礎,還有對微信小

Android 仿日報1

個人蠻喜歡沒事看看知乎的,前陣子湊巧也在網上搜到了知乎日報的API,詳情見某位開發者在Github上的分享:知乎日報 API 分析 靠著這個,我就做了一個高仿知乎日報的小應用 動態圖看起來不怎麼流暢,其實真機執行的話還是很流程的,畢竟這只是一個純

程式自定義屬性設定和獲取data-

自定義屬性語法以data-開頭: <block wx:for='{{post_key}}' wx:key="key" wx:for-item='item'> <view catchtap='onPostTap' data-postid="{{item.postId}}

程式視訊視訊背景與控制處理筆記

想用一個全屏的視訊當做小程式背景,然後呢,更坑爹啊,上傳單個素材2M限制。 注意: 1:用video元件時候,原生元件z-index無論如何都不會比他更高的,要用新的cover-view 2:視訊格式MP4支援AVC(H264)把你的視訊拖到chrome試試,就知道了。

程式免費HTTPS證書申請搭建教程1---申請SSL

背景: 最近微信小程式很火,技術迷的我自然要選擇跟風學習一下。按照微信小程式的官方文件,發出request請求連結地址必須為https。如果是使用http訪問請求,那麼在使用微信webapp開發工具時,如果像下面一樣勾選“不校驗請求域名以及TLS版本”,則可以使用開發環境的

程式免費HTTPS證書申請搭建教程2---安裝SSL並使用HTTPS訪問

繼續接上一節http://blog.csdn.net/mybelief321/article/details/54429314 上一節我們已經獲取了SSL證書,並下載到本地,現在以我的伺服器為例,把SSL證書安裝到伺服器並支援HTTPS訪問。 我的雲伺服器系統版本是Ubun

程式 開發過程中遇到的坑

1.我們使用app.json檔案來對微信小程式進行全域性配置,決定頁面檔案的路徑、視窗表現、設定網路超時時間、設定多 tab 的時候在pages中寫註釋的時候回報錯。 例如: { "pages":[ //這是首頁面 "pages/

程式支援的所有場景值id表格

基礎庫 1.1.0 開始支援,低版本需做相容處理。 當前支援的場景值有: 場景值ID 說明 1001 發現欄小程式主入口,“最近使用”列表(基礎庫2.2.4版本起將包含“我的小程式”列表) 1005 頂部搜尋框的搜尋結果頁 1006

程式開發者工具原始碼看實現原理- - 程式架構設計

使用微信小程式開發已經很長時間了,對小程式開發已經相當熟練了;但是作為一名對技術有追求的前端開發,僅僅熟練掌握小程式的開發感覺還是不夠的,我們應該更進一步的去理解其背後實現的原理以及對應的考量,這可能會解釋我們在開發過程中遇到的一些疑惑,比如為啥小程式不能操作dom、小程式是web技術渲染還是native技術

程式開發者工具原始碼看實現原理- - 程式技術實現

wxml與wxss的轉換 1、wxml使用wcc轉換 2、wxss使用wcsc轉換 開發者工具主入口 檢視層頁面的實現 檢視層頁面實現技術細節 檢視層快速開啟原理 檢視層新開啟頁面流程 業務邏輯層頁面的實現 wxml與wxss的轉換 開啟小程式開發者工具,在除錯控制檯輸入openVendor就會開

程式開發者工具原始碼看實現原理- - 自適應佈局

從前面從微信小程式開發者工具原始碼看實現原理(一)- - 小程式架構設計可以知道,小程式大部分是通過web技術進行渲染的,也就是最終通過瀏覽器的dom tree + cssom來生成渲染樹;既然最終是通過css來繪製ui佈局,我們知道小程式提供的自適應css單位rpx在瀏覽器環境根本不被識別,所以小程式最終還

程序實戰--仿人民日報

com var his pack ces dot 們的 targe 包含 前言 開發的大致思路是:請求人民日報電子版網址,通過對響應的html文檔進行匹配,查找需要的資源(比如數字報圖片地址、每版標題、每版的文章等) 新建項目打開安裝好的“微信web開發者工具”,點擊“+”

程式德API-PoI地址搜尋

在開始開發前有幾步必要步驟: 1.進入高德地圖API官網,登陸,開發支援-微信小程式SDK,控制檯,應用管理,建立開發需要的key。注意:服務平臺,必須是微信小程式。key用於什麼開發就建立什麼平臺Key。 2.下載 amap-wx.js開發包,https://lbs.amap

程式德API之定位。

在開始開發前有幾步必要步驟: 1.進入高德地圖API官網,登陸,開發支援-微信小程式SDK,控制檯,應用管理,建立開發需要的key。注意:服務平臺,必須是微信小程式。key用於什麼開發就建立什麼平臺Key。 2.下載 amap-wx.js開發包,https://lbs.amap

使Atom支援程式程式碼格式wxml,wxss有顏色

在用Atom來瀏覽或者編輯微信小程式時的介面時全灰色文字怎麼辦?!! 如何讓wxml和wxs格式的程式碼像HTML,CSS變成高亮的呢。。 就像這樣 ↓↓↓↓↓↓↓ 修改步驟如下 1.在Atom中裝

程式基於德api地理/逆地理編碼獲取地址

1.先使用微信自帶方法wx.getLocation去獲取經緯度。 wx.getLocation({ type: 'wgs84', //預設為 wgs84 返回 gps 座標,gcj02 返回可用於 wx.openLocation 的座標  suc

程式——獲取到px轉化為rpx根據裝置寬動態設定元素寬

在專案中需要給一個view標籤動態的設定高度 首先,先通過呼叫wx.getSystemInfo獲取裝置資訊 可以獲取的資訊如下圖 wx.getSystemInfo({ success: function(res) { console.log

程式 --- CSS實現仿網易雲音樂播放介面效果黑膠唱片與唱針純CSS實現

下面程式碼的效果是網易雲音樂唱針和黑膠唱片的CSS效果實現方式,播放等並沒貼出來 實現效果的範圍 動態圖效果預覽: stylusW,panW是獲取系統寬度計算後的引數 w

程式-基於德地圖API實現天氣元件(動態效果)

#### 微信小程式-基於高德地圖API實現天氣元件(動態效果) ​ 在社群翻騰了許久,沒有找到合適的天氣外掛。迫不得已,只好借鑑網際網路上的`web`專案,手動遷移到小程式中使用。現在分享到網際網路社群中,幫助後續有需要的開發者。 > 1.元件介紹 **1.1 元件效果預覽圖** ​ 小程

程式之側邊欄滑動實現附完整原始碼

目錄 一、效果圖 二、原理解析 三、原始碼 四、專案下載 同類文章推薦: 更多幹貨關注公眾號: 一、效果圖 講什麼都不如直接上效果圖好,所以我們先來看下實現效果如何。 通過滑動螢幕,或者點選左上角的圖示按鈕,都能實現側邊欄的劃出效果。   &nb