中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

第三個頁面:構建新聞詳情頁面

發布時間:2020-07-17 06:11:53 來源:網絡 閱讀:3491 作者:ZeroOne01 欄目:移動開發

筆記內容:構建新聞詳情頁面
筆記日期:2018-01-09


從文章列表跳轉到新聞詳情頁(組件自定義屬性及獲取屬性)

在編寫從文章列表跳轉到新聞詳情頁的代碼之前,先來修改一下之前的頁面,之前我們編寫了兩個模板文件,但是還有兩個細節沒有完善好,一個是post.wxss中的.post-container樣式沒有移植到模板文件中,另一個是wxml模板文件中每句數據綁定代碼都需要通過item這個子元素去調用屬性,顯得有點麻煩,我們可以使用一種語法去解決這個問題。

1.首先將post.wxss中的.post-container樣式移植到模板文件中

2.解決item重復的問題,在post.wxml中將之前的 template 代碼修改為以下內容:

<template is="postItem" data="{{...item}}" />

然后模板文件中的數據綁定代碼就不需要重復使用item子元素進行屬性的調用了:

<!-- 模板文件需要使用template標簽包圍 -->
<template name="postItem">
  <view class='post-container'>
      <view class='post-author-date'>
        <image src='{{avatar}}' class='post-author'></image>
        <text class="post-date">{{date}}</text>
      </view>
      <text class='post-title'>{{title}}</text>
      <image class='post-image' src='{{imgSrc}}'></image>
      <text class='post-content'>{{content}}</text>
      <view class='post-like'>
        <image src='../../images/icon/chat.png' class='post-like-img'></image>
        <text class='post-like-font'>{{reading}}</text>
        <image src='../../images/icon/view.png' class='post-like-img'></image>
        <text class='post-like-font'>{{collection}}</text>
      </view>
    </view>
</template>

完成以上的修改后,就可以開始編寫新聞詳情頁的代碼了:

1.構建目錄文件結構:
第三個頁面:構建新聞詳情頁面

2.由于我們需要實現點擊一個文章列表中的文章就跳轉到該文章的詳情頁面,所以我們還得給每一個文章做一個標識符,不然誰知道你點的是哪篇文章。這個標識符可以寫在數據文件中,作為一個屬性存在,所以需要在數據文件中為每一個文章數據都加上一個屬性,我定義的屬性名稱是postId:

// 將數據整合成數組類型
var local_database = [
  {
    date: "Jan 06 2018",
    title: "正是蝦肥蟹壯時",
    imgSrc: "/images/post/crab.png",
    avatar: "/images/avatar/1.png",
    content: "“山明水凈夜來霜,數樹深紅出淺黃。試上高樓清入骨,豈如春色嗾人狂。”金秋時節,天高云淡,秋風送爽,氣候宜人。秋風秋陽中,碩果墜掛枝頭,玉米撫須含笑,高粱引頸高歌,豆莢飽滿圓潤。",
    reading: "112",
    collection: "96",
    postId:0,
  },
  {
    date: "Jan 03 2018",
    title: "比利·林恩的中場戰事",
    imgSrc: "/images/post/bl.png",
    avatar: "/images/avatar/2.png",
    content: "伊拉克戰爭時期,來自美國德州的19歲技術兵比利·林恩(喬·阿爾文 Joe Alwyn 飾)因為一段偶然拍攝的視頻而家喻戶曉。那是一次規模不大卻激烈非常的遭遇戰,戰斗中林恩所在的B班班長(范·迪塞爾 Vin Diesel 飾)遭到當地武裝分子的伏擊和劫持,而林恩為了營救班長不惜鋌而走險沖鋒陷陣。",
    reading: "92",
    collection: "65",
    postId: 1,
  },
  {
    date: "Jan 05 2018",
    title: "肖申克的救贖",
    imgSrc: "/images/post/xs.jpg",
    avatar: "/images/avatar/3.png",
    content: "20世紀40年代末,小有成就的青年銀行家安迪(蒂姆·羅賓斯 Tim Robbins 飾)因涉嫌殺害妻子及她的情人而鋃鐺入獄。在這座名為肖申克的監獄內,希望似乎虛無縹緲,終身監禁的懲罰無疑注定了安迪接下來灰暗絕望的人生。",
    reading: "92",
    collection: "65",
    postId: 2,
  },
  {
    date: "Jan 01 2018",
    title: "霸王別姬",
    imgSrc: "/images/post/bj.jpg",
    avatar: "/images/avatar/4.png",
    content: "段小樓(張豐毅)與程蝶衣(張國榮)是一對打小一起長大的師兄弟,兩人一個演生,一個飾旦,一向配合天衣無縫,尤其一出《霸王別姬》,更是譽滿京城,為此,兩人約定合演一輩子《霸王別姬》。但兩人對戲劇與人生關系的理解有本質不同,段小樓深知戲非人生,程蝶衣則是人戲不分。",
    reading: "92",
    collection: "65",
    postId: 3,
  },
  {
    date: "Jan 08 2018",
    title: "這個殺手不太冷",
    imgSrc: "/images/post/ss.jpg",
    avatar: "/images/avatar/5.png",
    content: "里昂(讓·雷諾飾)是名孤獨的×××,受人雇傭。一天,鄰居家小姑娘馬蒂爾達(納塔麗·波特曼飾)敲開他的房門,要求在他那里暫避殺身之禍。原來鄰居家的主人是警方緝毒組的眼線,只因貪污了一小包×××而遭惡警(加里·奧德曼飾)殺害全家的懲罰。",
    reading: "92",
    collection: "65",
    postId: 4,
  },
  {
    date: "Jan 04 2018",
    title: "阿甘正傳",
    imgSrc: "/images/post/ag.jpg",
    avatar: "/images/avatar/1.png",
    content: "阿甘(湯姆·漢克斯 飾)于二戰結束后不久出生在美國南方阿拉巴馬州一個閉塞的小鎮,他先天弱智,智商只有75,然而他的媽媽是一個性格堅強的女性,她常常鼓勵阿甘“傻人有傻福”,要他自強不息。",
    reading: "92",
    collection: "65",
    postId: 5,
  },
]

// 設置一個數據出口
module.exports = {
  // 輸出的是一個Array對象
  postList: local_database,
}

3.在post.wxml文件中增加一個view標簽,把template標簽包圍起來,因為template標簽只是相當于一個占位符,編譯之后這個標簽是不存在的。然后給這個view標簽注冊一個tap事件,并且自定義一個屬性進行postId的數據綁定:

<!-- 自定義屬性必須以 data- 為前綴,后面連接的單詞可以自定義 -->
<view catchtap="onPostTap" data-postId="{{item.postId}}">
      <template is="postItem" data="{{...item}}"/>
</view>

4.然后到post.js文件中增加一個事件函數:

onPostTap: function(event){
    // 從事件源中獲取postId數據
    var postId = event.currentTarget.dataset.postid;
    console.log("on post id is " + postId);
 },

event是事件源對象,是默認會傳入的參數,currentTarget是當前被觸發事件的目標對象,dataset是數據集對象,數據要從數據集對象中獲取。至于為什么是通過postid獲取數據而不是通過data-postId或者postId獲取,請參考下圖:
第三個頁面:構建新聞詳情頁面

如圖,可以看到,自定義屬性被編譯之后的名稱并不是原本的名稱,所以我們通過dataset數據集對象獲取自定義屬性的數據時需要以編譯后的名稱為準。

5.接著就可以開始實現頁面跳轉了,先在post-detail.wxml中編寫一段話:

<text>
  這是文章詳情頁面
</text>

然后再app.json中加上一段post-detail的信息配置,每當我們新增頁面都需要如此進行配置:

"pages/posts/post-detail/post-detail"

回到post.js中,編寫頁面跳轉代碼:

  onPostTap: function(event){
    // 從事件源中獲取postId數據
    var postId = event.currentTarget.dataset.postid;
    wx.navigateTo({
      url: 'post-detail/post-detail',
    })
  },

完成以上操作編譯之后現在點擊文章列表中的文章就可以跳轉到文章詳情頁面了:
第三個頁面:構建新聞詳情頁面


先靜后動,先構建新聞詳情頁面樣式

編寫post-detail.wxml代碼:

<view class='container'>
  <image src='/images/post/sls.jpg' class='head-iamge'></image>
  <image class='audio' src='/images/music/music-start.png'></image>
  <view class='author-date'>
    <image src='/images/avatar/2.png' class='avatar' ></image>
    <text class='author'>zero</text>
    <text class='const-text'>發表于</text>
    <text class='date'>3天前</text>
  </view>
  <text class='title'>審美的進化機制</text>
  <view class='tool'>
    <view class='circle-img'>
      <image src='/images/icon/collection.png'></image>
      <image class='share-img' src='/images/icon/share.png'></image>
    </view>
    <view class='horizon'></view>
  </view>
  <text class='detail'>2017年讀的書中,有一本書是《紐約時報》年度十佳(2017 Ten Best Books),即:《美的進化——達爾文被遺忘的擇偶理論如何塑造動物世界乃至我們》(The Evolution of Beauty: How Darwin’s Forgotten Theory of Mate Choice Shapes the Animal World — and Us)。時報網站刊登了英文版評介的譯文:如果一本科學書籍能做到有顛覆性,倡導女權主義,還能改變我們看待自己身體的方式,但同時主要還是關于鳥類的,那就是這本書了。普魯姆是一位鳥類學家,他為達爾文的另一個基本上被忽略了的雌雄淘汰理論進行了辯護。</text>
</view>

post-detail.wxss代碼:

.container {
  display: flex;
  flex-direction: column;
}

.head-iamge {
  width: 750rpx;
  height: 460rpx;
}

.author-date {
  flex-direction: row;
  margin-left: 30rpx;
  margin-top: 20rpx;
}

.avatar {
  height: 64rpx;
  width: 64rpx;
  vertical-align: middle;
}

.author {
  font-size: 30rpx;
  font-weight: 300;
  margin-left: 20rpx;
  vertical-align: middle;
  color: #666;
}

.const-text {
  font-size: 24rpx;
  color: #999;
  margin-left: 20rpx;
}

.date {
  font-size: 24rpx;
  margin-left: 30rpx;
  color: #999;
  vertical-align: middle;
}

.title {
  margin-left: 40rpx;
  font-size: 36rpx;
  font-weight: 700;
  margin-top: 30rpx;
  letter-spacing: 2px;
  color: #4b556c;
}

.tool {
  margin-top: 20rpx;
}

.circle-img {
  float: right;
  margin-right: 40rpx;
  vertical-align: middle;
}
.circle-img image{
  width: 90rpx;
  height: 90rpx;
}
.share-img {
  margin-left: 30rpx;
}

.horizon {
  width: 660rpx;
  height: 1px;
  background-color: #e5e5e5;
  vertical-align: middle;
  position: relative;
  top: 46rpx;
  margin: 0 auto;
  z-index: -99;
}

.detail{
  color: #666;
  margin-left: 30rpx;
  margin-top: 20rpx;
  margin-right: 30rpx;
  line-height: 44rpx;
  letter-spacing: 2px;
}

.audio{
  width: 102rpx;
  height: 110rpx;
  position: absolute;
  left: 50%;
  margin-left: -51rpx;
  top: 180rpx;
  opacity: 0.6;  // 設置透明度為0.6
}

app.wxss代碼:

text{
  font-family: MicroSoft Yahei;
  font-size: 24rpx;
}

完成效果:
第三個頁面:構建新聞詳情頁面


配置全局導航欄顏色

上面把基本的靜態頁面做完了,但是導航欄顏色還不太對,而且少了個標識文字,所以現在就來把這個位置的樣式完善好。
app.json文件內容:

{
  "pages": [
    "pages/welcome/welcome",
    "pages/posts/post",
    "pages/posts/post-detail/post-detail"
  ],
  "window": {
    "navigationBarBackgroundColor": "#405f80"
  }
}

welcome.json文件內容:

{
  "navigationBarBackgroundColor": "#b3d4db"
}

post.json文件內容:

{
    "navigationBarTitleText": "文與字"
}

post-detail.json文件內容:

{
  "navigationBarTitleText": "閱讀"
}

完成效果:
第三個頁面:構建新聞詳情頁面


使用數據填充新聞詳情頁面

首先是postId的獲得,因為不同的postId需要輸出不同的文章詳情數據:
1.在post.js的navigateTo方法的url參數中,加上一個id參數:

onPostTap: function(event){
    // 從事件源中獲取postId數據
    var postId = event.currentTarget.dataset.postid;
    //console.log("on post id is " + postId);
    wx.navigateTo({
      url: 'post-detail/post-detail?id=' + postId,  // 通過url傳遞postId
    })
  },

2.然后在post-detail.js中,寫一個onLoad函數把id獲得到手:

Page({
  onLoad:function(option){
    var postId = option.id; // 這里的id對應的是url參數上的id
    console.log(postId);
  }
})

3.編譯之后,點擊不同的文章,看看控制臺中是否有輸出相應的postId,有輸出的話就證明獲得成功。

完成以上操作后,就可以把新聞詳情頁面的數據放進數據文件中,然后進行數據綁定:
post-data.js文件內容:

// 將數據整合成數組類型
var local_database = [
  {
    date: "Jan 06 2018",
    title: "正是蝦肥蟹壯時",
    imgSrc: "/images/post/crab.png",
    avatar: "/images/avatar/1.png",
    content: "“山明水凈夜來霜,數樹深紅出淺黃。試上高樓清入骨,豈如春色嗾人狂。”金秋時節,天高云淡,秋風送爽,氣候宜人。秋風秋陽中,碩果墜掛枝頭,玉米撫須含笑,高粱引頸高歌,豆莢飽滿圓潤。",
    reading: "112",
    collection: "96",
    headImgSrc: "/images/post/crab.png",
    author: "zero",
    dataTime:"24小時前",
    detail: "“山明水凈夜來霜,數樹深紅出淺黃。試上高樓清入骨,豈如春色嗾人狂。”金秋時節,天高云淡,秋風送爽,氣候宜人。秋風秋陽中,碩果墜掛枝頭,玉米撫須含笑,高粱引頸高歌,豆莢飽滿圓潤。棉桃鼓脹欲裂,水稻灌漿初熟,世間萬物經過春的孕育,夏的生長,即將抵達收獲的季節。在這瓜果飄香、稻黍起舞的召喚聲中,又是一度蟹肥蝦壯時。地處黃海之濱的小城,在秋風的撫慰、秋陽的光照下,瞬間也喧囂起來。任意走進城中的每一個菜市場,在顯眼的位置上,沖入耳際的是此起彼伏的吆喝聲,映入眼簾的是那些小商小販們搶占有利地勢將一只只塑料箱一字排開的情景。淺箱中,健壯的對蝦、竹節蝦在水中跳躍,舒展著彎曲的身體;深箱中,一貫橫行霸道的螃蟹擁擠在狹小的空間里,相互肆意踐踏,有些不甘蝸居的螃蟹,順著筆直的箱壁艱難地攀爬著,雖經百般努力,終以失敗而告終。那些聚集在網兜里的螃蟹,更是不甘寂寞,身體被束縛著無法動彈,便利用可以自由呼吸的嘴巴,于窸窸窣窣中不停地吐著一串串泡沫,以示抗議,也以此證明自己是個活物。特別是那些個頭較大的螃蟹,仿佛知道自己的身價不菲,為此,更是氣宇軒昂,自以為是。也許,它們是得到垂青和恩寵的一類吧,受到了特別的眷顧,活動的空間相對較大,所以也更加肆無忌憚。只要有人試圖靠近,便會舉著那兩只肥碩的大螯向你示威,仿佛在警告你:別碰我,否則休怪我無禮!",
    postId: 0,
  },
  {
    date: "Jan 03 2018",
    title: "比利·林恩的中場戰事",
    imgSrc: "/images/post/bl.png",
    avatar: "/images/avatar/2.png",
    content: "伊拉克戰爭時期,來自美國德州的19歲技術兵比利·林恩(喬·阿爾文 Joe Alwyn 飾)因為一段偶然拍攝的視頻而家喻戶曉。那是一次規模不大卻激烈非常的遭遇戰,戰斗中林恩所在的B班班長(范·迪塞爾 Vin Diesel 飾)遭到當地武裝分子的伏擊和劫持,而林恩為了營救班長不惜鋌而走險沖鋒陷陣。",
    reading: "92",
    collection: "65",
    headImgSrc: "/images/post/bl.png",
    dataTime: "一天前",
    author: "妮可",
    detail: "伊拉克戰爭時期,來自美國德州的19歲技術兵比利·林恩(喬·阿爾文 Joe Alwyn 飾)因為一段偶然拍攝的視頻而家喻戶曉。那是一次規模不大卻激烈非常的遭遇戰,戰斗中林恩所在的B班班長(范·迪塞爾 Vin Diesel 飾)遭到當地武裝分子的伏擊和劫持,而林恩為了營救班長不惜鋌而走險沖鋒陷陣。視頻公布于世讓他成為全美民眾所崇拜的英雄,然而卻鮮有人理解他和戰友們所經歷的一切。為了安葬班長,B班得到了短暫的休假,因此他們得以受邀參加一場在德州舉行的橄欖球比賽。林恩的姐姐因某事件深感愧疚,她希望弟弟能借此機緣回歸普通生活。而周圍的經紀人、球迷、大老板、普通民眾則對戰爭、衛國、士兵有著各種各樣想當然的理解。球場上的慶典盛大開幕,林恩和戰友們的心卻愈加沉重與焦躁…… ",
    postId: 1,
  },
  {
    date: "Jan 05 2018",
    title: "肖申克的救贖",
    imgSrc: "/images/post/xs.jpg",
    avatar: "/images/avatar/3.png",
    content: "20世紀40年代末,小有成就的青年銀行家安迪(蒂姆·羅賓斯 Tim Robbins 飾)因涉嫌殺害妻子及她的情人而鋃鐺入獄。在這座名為肖申克的監獄內,希望似乎虛無縹緲,終身監禁的懲罰無疑注定了安迪接下來灰暗絕望的人生。",
    reading: "92",
    collection: "65",
    headImgSrc: "/images/post/xs.jpg",
    dataTime: "兩天前",
    author: "John",
    detail: "20世紀40年代末,小有成就的青年銀行家安迪(蒂姆·羅賓斯 Tim Robbins 飾)因涉嫌殺害妻子及她的情人而鋃鐺入獄。在這座名為肖申克的監獄內,希望似乎虛無縹緲,終身監禁的懲罰無疑注定了安迪接下來灰暗絕望的人生。未過多久,安迪嘗試接近囚犯中頗有聲望的瑞德(摩根·弗里曼 Morgan Freeman 飾),請求對方幫自己搞來小錘子。以此為契機,二人逐漸熟稔,安迪也仿佛在魚龍混雜、罪惡橫生、黑白混淆的牢獄中找到屬于自己的求生之道。他利用自身的專業知識,幫助監獄管理層逃稅、洗黑錢,同時憑借與瑞德的交往在×××中間也漸漸受到禮遇。表面看來,他已如瑞德那樣對那堵高墻從憎恨轉變為處之泰然,但是對自由的渴望仍促使他朝著心中的希望和目標前進。而關于其罪行的真相,似乎更使這一切朝前推進了一步…… ",
    postId: 2,
  },
  {
    date: "Jan 01 2018",
    title: "霸王別姬",
    imgSrc: "/images/post/bj.jpg",
    avatar: "/images/avatar/4.png",
    content: "段小樓(張豐毅)與程蝶衣(張國榮)是一對打小一起長大的師兄弟,兩人一個演生,一個飾旦,一向配合天衣無縫,尤其一出《霸王別姬》,更是譽滿京城,為此,兩人約定合演一輩子《霸王別姬》。但兩人對戲劇與人生關系的理解有本質不同,段小樓深知戲非人生,程蝶衣則是人戲不分。",
    reading: "92",
    collection: "65",
    headImgSrc: "/images/post/bj.jpg",
    dataTime: "三天前",
    author: "Jack",
    detail: "段小樓(張豐毅)與程蝶衣(張國榮)是一對打小一起長大的師兄弟,兩人一個演生,一個飾旦,一向配合天衣無縫,尤其一出《霸王別姬》,更是譽滿京城,為此,兩人約定合演一輩子《霸王別姬》。但兩人對戲劇與人生關系的理解有本質不同,段小樓深知戲非人生,程蝶衣則是人戲不分。段小樓在認為該成家立業之時迎娶了名妓菊仙(鞏俐),致使程蝶衣認定菊仙是可恥的第三者,使段小樓做了叛徒,自此,三人圍繞一出《霸王別姬》生出的愛恨情仇戰開始隨著時代風云的變遷不斷升級,終釀成悲劇。",
    postId: 3,
  },
  {
    date: "Jan 08 2018",
    title: "這個殺手不太冷",
    imgSrc: "/images/post/ss.jpg",
    avatar: "/images/avatar/5.png",
    content: "里昂(讓·雷諾飾)是名孤獨的×××,受人雇傭。一天,鄰居家小姑娘馬蒂爾達(納塔麗·波特曼飾)敲開他的房門,要求在他那里暫避殺身之禍。原來鄰居家的主人是警方緝毒組的眼線,只因貪污了一小包×××而遭惡警(加里·奧德曼飾)殺害全家的懲罰。",
    reading: "92",
    collection: "65",
    headImgSrc: "/images/post/ss.jpg",
    dataTime: "四天前",
    author: "Bill",
    detail: "里昂(讓·雷諾飾)是名孤獨的×××,受人雇傭。一天,鄰居家小姑娘馬蒂爾達(納塔麗·波特曼飾)敲開他的房門,要求在他那里暫避殺身之禍。原來鄰居家的主人是警方緝毒組的眼線,只因貪污了一小包×××而遭惡警(加里·奧德曼飾)殺害全家的懲罰。馬蒂爾達得到里昂的留救,幸免于難,并留在里昂那里。里昂教小女孩使槍,她教里昂法文,兩人關系日趨親密,相處融洽。女孩想著去×××,反倒被抓,里昂及時趕到,將女孩救回。混雜著哀怨情仇的正邪之戰漸次升級,更大的沖突在所難免…… ",
    postId: 4,
  },
  {
    date: "Jan 04 2018",
    title: "阿甘正傳",
    imgSrc: "/images/post/ag.jpg",
    avatar: "/images/avatar/1.png",
    content: "阿甘(湯姆·漢克斯 飾)于二戰結束后不久出生在美國南方阿拉巴馬州一個閉塞的小鎮,他先天弱智,智商只有75,然而他的媽媽是一個性格堅強的女性,她常常鼓勵阿甘“傻人有傻福”,要他自強不息。",
    reading: "92",
    collection: "65",
    headImgSrc: "/images/post/ag.jpg",
    dataTime: "五天前",
    author: "Tony",
    detail: "阿甘(湯姆·漢克斯 飾)于二戰結束后不久出生在美國南方阿拉巴馬州一個閉塞的小鎮,他先天弱智,智商只有75,然而他的媽媽是一個性格堅強的女性,她常常鼓勵阿甘“傻人有傻福”,要他自強不息。阿甘像普通孩子一樣上學,并且認識了一生的朋友和至愛珍妮(羅賓·萊特·潘 飾),在珍妮和媽媽的愛護下,阿甘憑著上帝賜予的“飛毛腿”開始了一生不停的奔跑。阿甘成為橄欖球巨星、越戰英雄、乒乓球外交使者、億萬富翁,但是,他始終忘不了珍妮,幾次匆匆的相聚和離別,更是加深了阿甘的思念。有一天,阿甘收到珍妮的信,他們終于又要見面了……",
    postId: 5,
  },
]

// 設置一個數據出口
module.exports = {
  // 輸出的是一個Array對象
  postList: local_database,
}

post-detail.js文件內容:

var postsData = require('../../../data/posts-data.js')

Page({
  onLoad:function(option){
    var postId = option.id; // 這里的id對應的是url參數上的id
    var postData=postsData.postList[postId];
    this.setData({
        postData
    });
  }
})

post-detail.wxml文件內容:

<view class='container'>
  <image src='{{postData.headImgSrc}}' class='head-iamge'></image>
  <image class='audio' src='/images/music/music-start.png'></image>
  <view class='author-date'>
    <image src='{{postData.avatar}}' class='avatar' ></image>
    <text class='author'>{{postData.author}}</text>
    <text class='const-text'>發表于</text>
    <text class='date'>{{postData.dataTime}}</text>
  </view>
  <text class='title'>{{postData.title}}</text>
  <view class='tool'>
    <view class='circle-img'>
      <image src='/images/icon/collection.png'></image>
      <image class='share-img' src='/images/icon/share.png'></image>
    </view>
    <view class='horizon'></view>
  </view>
  <text class='detail'>{{postData.detail}}</text>
</view>

運行效果:
第三個頁面:構建新聞詳情頁面


緩存Storage的基本用法

在文章詳情頁中我們需要實現一個文章收藏的功能,由于我們沒有使用到服務器,所以使用本地緩存來記錄這個文章是否被用戶收藏的一個狀態。

小程序中提供了一個setStorageSync方法來實現緩存,從方法名也可以看出這個方法是帶有同步的。除此之外還有一個異步的緩存方法setStorage,這個方法可以用于異步緩存數據。

注:和緩存相關的方法,例如得到緩存數據、刪除緩存數據等方法,都有同步和異步兩個,方法名末尾有Sync的表示同步,否則是異步。

首先演示一下setStorageSync方法的使用方式:

// 第一個參數是鍵,第二個參數則是需要存儲的數據
wx.setStorageSync('key', "Test");

我在post-detail.js文件中的onLoad方法里加入了以上這段代碼,此時我點擊進入文章詳情頁面,就會緩存這個數據,緩存數據在Storage界面查看:
第三個頁面:構建新聞詳情頁面

在小程序中,如果用戶不去主動清除緩存數據,那么數據就會一直存在,所以現在即便我關閉開發工具或者重新進行編譯,這個數據都會存在,除非我主動刪掉它。

通過鍵可以改變緩存數據:

wx.setStorageSync('key', {
      game:"eat chicken",
      developer:"LD",
});

運行結果:
第三個頁面:構建新聞詳情頁面

獲取緩存的數據:

<!-- 在收藏圖標上加上一個事件 -->
<image catchtap='onCollectionTap' src='/images/icon/collection.png'></image>

使用getStorageSync方法即可得到緩存數據:

onCollectionTap:function(event){
    var game=wx.getStorageSync('key');
    console.log(game);
}

運行結果:
第三個頁面:構建新聞詳情頁面

刪除緩存數據:

<!-- 在分享圖標上加上一個事件 -->
<image catchtap='onShareTap' class='share-img' src='/images/icon/share.png'></image>

使用removeStorageSync方法即可刪除緩存數據:

onShareTap:function(event){
    wx.removeStorageSync('key');
},

運行結果,可以看到數據已經不存在了:
第三個頁面:構建新聞詳情頁面

刪除所有緩存數據的方法:

wx.clearStorageSync();

注:小程序規定緩存數據的大小上限是10MB


使用緩存實現文章收藏功能

實現這個功能我們需要使用到兩個圖標進行狀態的輪換,由于小程序中沒有document,我們需要使用if判斷來實現這個功能。

post-detail.wxml代碼如下:

<!-- 判斷collected的值是否為真,是的話就顯示src中指定的圖片 -->
<image wx:if="{{collected}}" catchtap='onCollectionTap' src='/images/icon/collection.png'></image>
<!-- 否則顯示這張圖片 -->
<image wx:else catchtap='onCollectionTap' src='/images/icon/collection-anti.png'></image>

post-detail.js代碼如下:

var postsData = require('../../../data/posts-data.js')

Page({
  data:{

  },
  onLoad: function (option) {
    var postId = option.id; // 這里的id對應的是url參數上的id
    // 把postId設置到數據集里,這樣就能夠全局獲取
    this.data.currentPostId = postId;
    var postData = postsData.postList[postId];
    this.setData({
      postData
    });

    // 從緩存中獲取數據,鍵值對形式的
    var postsCollected = wx.getStorageSync('posts_collected');
    // 判斷數據是否不為空
    if (postsCollected) {
      // 不為空就拿出與postId對應的下標值
      var postsCollected = postsCollected[postId];
      // 并將值更新到數據綁定里
      this.setData({
        collected: postsCollected
      });
    } else {
      // 如果為空就賦值一個空對象
      var postsCollected = {}
      // 并把與postId對應的下標中的值設置為false
      postsCollected[postId] = false;
      // 更新到緩存里
      wx.setStorageSync('posts_collected', postsCollected);
    }
  },

  // 點擊事件方法
  onCollectionTap: function (event) {
    // 獲取緩存數據
    var postsCollected = wx.getStorageSync('posts_collected');
    // 從數據集中獲取postId
    var postCollected = postsCollected[this.data.currentPostId];
    // 收藏變成未收藏,未收藏變成收藏
    postCollected = !postCollected;
    postsCollected[this.data.currentPostId] = postCollected;
    // 更新文章是否收藏的緩存值
    wx.setStorageSync('posts_collected', postsCollected);
    // 更新數據綁定變量,從而實現切換圖片
    this.setData({
      collected: postCollected
    });
  },

})

運行效果:

未收藏狀態:
第三個頁面:構建新聞詳情頁面

收藏狀態:
第三個頁面:構建新聞詳情頁面


交互反饋 wx.showToast

以上我們實現了收藏和未收藏圖標的一個輪換功能,但是還缺少了個提示功能,在用戶點擊收藏時要提示用戶收藏成功,再次點擊則需要提示用戶取消成功。

小程序提供了幾個實現交互反饋功能的API,詳情參考以下官方文檔:

https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-react.html

我們需要使用到其中三個API,分別是wx.showToast、wx.showModal、wx.showActionSheet。

首先來應用wx.showToast這個API,在事件方法中,加入如下代碼:

wx.showToast({
      // 使用三元表達式來判斷狀態
      title: postCollected ? '收藏成功!' :'取消成功!',
      // 設置圖標停留的時間,單位是毫秒
      duration: 1000,
      // icon可以設置圖標,默認就是success
      icon: "success",
});

運行效果:
第三個頁面:構建新聞詳情頁面
第三個頁面:構建新聞詳情頁面


操作反饋wx.showModal

wx.showModal可以顯示模態彈窗,我們可以把wx.showModal與wx.showToast相結合使用。

修改代碼如下:

var postsData = require('../../../data/posts-data.js')

Page({
  data: {

  },
  onLoad: function (option) {
    var postId = option.id; // 這里的id對應的是url參數上的id
    // 把postId設置到數據集里,這樣就能夠全局獲取
    this.data.currentPostId = postId;
    var postData = postsData.postList[postId];
    this.setData({
      postData
    });

    // 從緩存中獲取數據
    var postsCollected = wx.getStorageSync('posts_collected');
    // 判斷數據是否不為空
    if (postsCollected) {
      // 不為空就拿出與postId對應的下標值
      var postsCollected = postsCollected[postId];
      // 并將值更新到數據綁定里
      this.setData({
        collected: postsCollected
      });
    } else {
      // 如果為空就賦值一個空對象
      var postsCollected = {}
      // 并把與postId對應的下標中的值設置為false
      postsCollected[postId] = false;
      // 更新到緩存里
      wx.setStorageSync('posts_collected', postsCollected);
    }
  },

  // 點擊事件方法
  onCollectionTap: function (event) {
    // 獲取緩存數據
    var postsCollected = wx.getStorageSync('posts_collected');
    // 獲取postId
    var postCollected = postsCollected[this.data.currentPostId];
    // 收藏變成未收藏,未收藏變成收藏
    postCollected = !postCollected;
    postsCollected[this.data.currentPostId] = postCollected;

    // 自定義函數也需要使用this來訪問
    this.showModal(postsCollected, postCollected);
  },

  showModal: function (postsCollected, postCollected){
    // 把this指代的Page對象先存儲起來
    var that = this;
    wx.showModal({
      title: '收藏',
      content: postCollected ? '是否收藏該文章?' :'是否取消收藏該文章?',
      showCancel: 'true',
      cancelText: '取消',
      cancelColor: '#333',
      confirmText: '確認',
      confirmColor: '#405f80',
      success:function(res){
        if(res.confirm){
          // 更新文章是否收藏的緩存值
          wx.setStorageSync('posts_collected', postsCollected);
          // 更新數據綁定變量,從而實現切換圖片
          that.setData({
            collected: postCollected
          });
          that.showToast(postsCollected, postCollected);
        }
      },
    });
  },

  showToast: function (postsCollected, postCollected){
    wx.showToast({
      // 使用三元表達式來判斷狀態
      title: postCollected ? '收藏成功!' : '取消成功!',
      // 設置圖標停留的時間,單位是毫秒
      duration: 1000,
      // icon可以設置圖標,默認就是success
      icon: "success",
    });
  },
})

運行效果:
收藏:
第三個頁面:構建新聞詳情頁面
第三個頁面:構建新聞詳情頁面

取消收藏:
第三個頁面:構建新聞詳情頁面
第三個頁面:構建新聞詳情頁面

注:在實際開發中這種成本低的操作是不需要把交互反饋做得這么麻煩的,一般只使用showToast即可。所謂成本指的是誤操作帶來的損失,如果成本低的操作交互反饋太麻煩的話,會感覺體驗不好。


交互反饋wx.showActionSheet

?showActionSheet可以顯示操作菜單,以下使用實際示例演示一下showActionSheet的使用:

1.在分享圖標上加上一個點擊事件:

<image catchtap='onShareTap' class='share-img' src='/images/icon/share.png'></image>

2.事件代碼如下:

onShareTap:function(event){
    var itemList = [
      "分享給微信好友",
      "分享到朋友圈",
      "分享到QQ",
      "分享到微博",
    ]
    wx.showActionSheet({
      itemList: itemList,  // 按鈕的文字數組,數組長度最大為6個
      itemColor:"#405f80",  // 設置字體顏色
      success:function(res){
        //res.tapIndex  用戶點擊的按鈕,從上到下的順序,從0開始
        wx.showModal({
          title: itemList[res.tapIndex],
          content: '現在無法實現分享功能,什么時候能支持還未知',
        })
      }, 
    })
  },

運行效果:
第三個頁面:構建新聞詳情頁面
第三個頁面:構建新聞詳情頁面

注:到目前為止,微信小程序官方還尚未提供能夠將小程序直接分享到朋友圈的相關api,不過有一些曲線救國的方案,可以參考以下兩篇文章,或者使用百度、谷歌等搜索引擎搜索解決方案:

https://segmentfault.com/a/1190000012316892
http://blog.csdn.net/baozhuona/article/details/78570483


同步異步方法對比

我們把之前的onCollectionTap方法中的同步獲取緩存的方法改為異步獲取緩存的方法,以此來演示同步與異步方法之間的區別,修改代碼如下:

onCollectionTap: function (event) {
    // 把當前this指代的當前對象先存儲起來
    var that = this;
    // 異步獲取緩存數據
    var postsCollected = wx.getStorage({
      key: 'posts_collected',
      success: function (res) {
        var postsCollected = res.data;
        // 獲取postId
        var postCollected = postsCollected[that.data.currentPostId];
        // 收藏變成未收藏,未收藏變成收藏
        postCollected = !postCollected;
        postsCollected[that.data.currentPostId] = postCollected;

        that.showModal(postsCollected, postCollected);
      },
    });
  },

以上就是異步方法的實現方式,與同步方法的主要區別在于,同步會等待wx.getStorageSync('posts_collected');方法執行完之后才會往下執行,所以如果當獲取緩存得很慢的時候,操作界面就會卡在那。而異步則不會,異步獲取緩存數據的時候,代碼還會繼續往下執行,異步獲取完成之后再執行success里的方法。

注:通常情況下,在小程序中必須要使用異步方法的情況比較少,建議如果對異步方法不熟悉的話,最好不要使用異步方法,不然不僅會讓你的代碼變得難以閱讀,而且很容易埋下一些隱藏bug,或者難以解決的錯誤。至于使用異步還是同步,需要根據業務來決定,當可以使用同步的情況下,優先使用同步。


音樂播放基本實現

以上我們已經完成了文章詳情頁的大部分內容,現在還剩一個音樂播放功能還未實現,官方也提供了一個audio組件可以實現音樂播放。除了組件之外還有相關的API可以使用,在這里我們使用API來實現音樂播放功能,因為使用API的方式比較方便于自定義。

官方文檔:

API:https://mp.weixin.qq.com/debug/wxadoc/dev/api/media-voice.html
組件:https://mp.weixin.qq.com/debug/wxadoc/dev/component/audio.html

我們需要使用到兩個API,playBackgroundAudio以及pauseBackgroundAudio。前者是用于音樂的播放,后者是用于音樂的暫停。

先給音樂圖標添加一個事件,并且使用三元運算符來判斷圖標是顯示暫停圖標還是啟動圖標:

<image catchtap='onMusicTap' class='audio' src='{{isPlayingMusic ? "/images/music/music-stop.png" : "/images/music/music-start.png"}}'></image>

事件方法實現代碼如下:

data: {
    isPlayingMusic: false
},

onMusicTap: function (event) {
    // 獲取數據文件中的數據
    var currentPostId = this.data.currentPostId;
    var postData = postsData.postList[currentPostId];

    // 使用變量來記錄音樂的狀態
    var isPlayingMusic = this.data.isPlayingMusic;
    if (isPlayingMusic) {
      // 暫停音樂
      wx.pauseBackgroundAudio();
      // 改變狀態
      this.setData({
        isPlayingMusic : false
      });

    } else {
      wx.playBackgroundAudio({
        // 流媒體文件的URL,目前支持的格式有 m4a, aac, mp3, wav
        dataUrl: postData.music.url,
        // 音樂標題
        title: postData.music.title,
        // 音樂封面URL
        coverImgUrl: postData.music.coverImg,
      })
      // 改變狀態
      this.setData({
        isPlayingMusic: true
      });
    }
  },

注:dataUrl只能夠是引用流媒體文件,不能夠使用本地的音樂文件,coverImgUrl也是如此,因為小程序的大小限制是1M,一個音樂文件都不止1M了,所以只能使用流媒體文件的URL形式引入音樂。coverImgUrl引入的圖片只有在真機上才能看到得到。

數據文件內容如下,增加了音樂連接、音樂標題、音樂圖片屬性:

// 將數據整合成數組類型
var local_database = [
  {
    date: "Jan 06 2018",
    title: "正是蝦肥蟹壯時",
    imgSrc: "/images/post/crab.png",
    avatar: "/images/avatar/1.png",
    content: "“山明水凈夜來霜,數樹深紅出淺黃。試上高樓清入骨,豈如春色嗾人狂。”金秋時節,天高云淡,秋風送爽,氣候宜人。秋風秋陽中,碩果墜掛枝頭,玉米撫須含笑,高粱引頸高歌,豆莢飽滿圓潤。",
    reading: "112",
    collection: "96",
    headImgSrc: "/images/post/crab.png",
    author: "zero",
    dataTime:"24小時前",
    detail: "“山明水凈夜來霜,數樹深紅出淺黃。試上高樓清入骨,豈如春色嗾人狂。”金秋時節,天高云淡,秋風送爽,氣候宜人。秋風秋陽中,碩果墜掛枝頭,玉米撫須含笑,高粱引頸高歌,豆莢飽滿圓潤。棉桃鼓脹欲裂,水稻灌漿初熟,世間萬物經過春的孕育,夏的生長,即將抵達收獲的季節。在這瓜果飄香、稻黍起舞的召喚聲中,又是一度蟹肥蝦壯時。地處黃海之濱的小城,在秋風的撫慰、秋陽的光照下,瞬間也喧囂起來。任意走進城中的每一個菜市場,在顯眼的位置上,沖入耳際的是此起彼伏的吆喝聲,映入眼簾的是那些小商小販們搶占有利地勢將一只只塑料箱一字排開的情景。淺箱中,健壯的對蝦、竹節蝦在水中跳躍,舒展著彎曲的身體;深箱中,一貫橫行霸道的螃蟹擁擠在狹小的空間里,相互肆意踐踏,有些不甘蝸居的螃蟹,順著筆直的箱壁艱難地攀爬著,雖經百般努力,終以失敗而告終。那些聚集在網兜里的螃蟹,更是不甘寂寞,身體被束縛著無法動彈,便利用可以自由呼吸的嘴巴,于窸窸窣窣中不停地吐著一串串泡沫,以示抗議,也以此證明自己是個活物。特別是那些個頭較大的螃蟹,仿佛知道自己的身價不菲,為此,更是氣宇軒昂,自以為是。也許,它們是得到垂青和恩寵的一類吧,受到了特別的眷顧,活動的空間相對較大,所以也更加肆無忌憚。只要有人試圖靠近,便會舉著那兩只肥碩的大螯向你示威,仿佛在警告你:別碰我,否則休怪我無禮!",
    postId: 0,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100003507bR0gDKBm.m4a?fromtag=38",
      title: "夜夜夜夜-齊秦",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000001TEc6V0kjpVC.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 03 2018",
    title: "比利·林恩的中場戰事",
    imgSrc: "/images/post/bl.png",
    avatar: "/images/avatar/2.png",
    content: "伊拉克戰爭時期,來自美國德州的19歲技術兵比利·林恩(喬·阿爾文 Joe Alwyn 飾)因為一段偶然拍攝的視頻而家喻戶曉。那是一次規模不大卻激烈非常的遭遇戰,戰斗中林恩所在的B班班長(范·迪塞爾 Vin Diesel 飾)遭到當地武裝分子的伏擊和劫持,而林恩為了營救班長不惜鋌而走險沖鋒陷陣。",
    reading: "92",
    collection: "65",
    headImgSrc: "/images/post/bl.png",
    dataTime: "一天前",
    author: "妮可",
    detail: "伊拉克戰爭時期,來自美國德州的19歲技術兵比利·林恩(喬·阿爾文 Joe Alwyn 飾)因為一段偶然拍攝的視頻而家喻戶曉。那是一次規模不大卻激烈非常的遭遇戰,戰斗中林恩所在的B班班長(范·迪塞爾 Vin Diesel 飾)遭到當地武裝分子的伏擊和劫持,而林恩為了營救班長不惜鋌而走險沖鋒陷陣。視頻公布于世讓他成為全美民眾所崇拜的英雄,然而卻鮮有人理解他和戰友們所經歷的一切。為了安葬班長,B班得到了短暫的休假,因此他們得以受邀參加一場在德州舉行的橄欖球比賽。林恩的姐姐因某事件深感愧疚,她希望弟弟能借此機緣回歸普通生活。而周圍的經紀人、球迷、大老板、普通民眾則對戰爭、衛國、士兵有著各種各樣想當然的理解。球場上的慶典盛大開幕,林恩和戰友們的心卻愈加沉重與焦躁…… ",
    postId: 1,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100003GdCmG4NkEOR.m4a?fromtag=38",
      title: "鬼迷心竅-李宗盛",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000002xOmp62kqSic.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 05 2018",
    title: "肖申克的救贖",
    imgSrc: "/images/post/xs.jpg",
    avatar: "/images/avatar/3.png",
    content: "20世紀40年代末,小有成就的青年銀行家安迪(蒂姆·羅賓斯 Tim Robbins 飾)因涉嫌殺害妻子及她的情人而鋃鐺入獄。在這座名為肖申克的監獄內,希望似乎虛無縹緲,終身監禁的懲罰無疑注定了安迪接下來灰暗絕望的人生。",
    reading: "92",
    collection: "65",
    headImgSrc: "/images/post/xs.jpg",
    dataTime: "兩天前",
    author: "John",
    detail: "20世紀40年代末,小有成就的青年銀行家安迪(蒂姆·羅賓斯 Tim Robbins 飾)因涉嫌殺害妻子及她的情人而鋃鐺入獄。在這座名為肖申克的監獄內,希望似乎虛無縹緲,終身監禁的懲罰無疑注定了安迪接下來灰暗絕望的人生。未過多久,安迪嘗試接近囚犯中頗有聲望的瑞德(摩根·弗里曼 Morgan Freeman 飾),請求對方幫自己搞來小錘子。以此為契機,二人逐漸熟稔,安迪也仿佛在魚龍混雜、罪惡橫生、黑白混淆的牢獄中找到屬于自己的求生之道。他利用自身的專業知識,幫助監獄管理層逃稅、洗黑錢,同時憑借與瑞德的交往在×××中間也漸漸受到禮遇。表面看來,他已如瑞德那樣對那堵高墻從憎恨轉變為處之泰然,但是對自由的渴望仍促使他朝著心中的希望和目標前進。而關于其罪行的真相,似乎更使這一切朝前推進了一步…… ",
    postId: 2,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100004HLusI2lLjZy.m4a?fromtag=38",
      title: "女兒情-萬曉利",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000004Wv5BO30pPc0.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 01 2018",
    title: "霸王別姬",
    imgSrc: "/images/post/bj.jpg",
    avatar: "/images/avatar/4.png",
    content: "段小樓(張豐毅)與程蝶衣(張國榮)是一對打小一起長大的師兄弟,兩人一個演生,一個飾旦,一向配合天衣無縫,尤其一出《霸王別姬》,更是譽滿京城,為此,兩人約定合演一輩子《霸王別姬》。但兩人對戲劇與人生關系的理解有本質不同,段小樓深知戲非人生,程蝶衣則是人戲不分。",
    reading: "92",
    collection: "65",
    headImgSrc: "/images/post/bj.jpg",
    dataTime: "三天前",
    author: "Jack",
    detail: "段小樓(張豐毅)與程蝶衣(張國榮)是一對打小一起長大的師兄弟,兩人一個演生,一個飾旦,一向配合天衣無縫,尤其一出《霸王別姬》,更是譽滿京城,為此,兩人約定合演一輩子《霸王別姬》。但兩人對戲劇與人生關系的理解有本質不同,段小樓深知戲非人生,程蝶衣則是人戲不分。段小樓在認為該成家立業之時迎娶了名妓菊仙(鞏俐),致使程蝶衣認定菊仙是可恥的第三者,使段小樓做了叛徒,自此,三人圍繞一出《霸王別姬》生出的愛恨情仇戰開始隨著時代風云的變遷不斷升級,終釀成悲劇。",
    postId: 3,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100002mWVx72p8Ugp.m4a?fromtag=38",
      title: "戀戀風塵-老狼",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000001VaXQX1Z1Imq.jpg?max_age=2592000",
    }
  },
  {
    date: "Jan 08 2018",
    title: "這個殺手不太冷",
    imgSrc: "/images/post/ss.jpg",
    avatar: "/images/avatar/5.png",
    content: "里昂(讓·雷諾飾)是名孤獨的×××,受人雇傭。一天,鄰居家小姑娘馬蒂爾達(納塔麗·波特曼飾)敲開他的房門,要求在他那里暫避殺身之禍。原來鄰居家的主人是警方緝毒組的眼線,只因貪污了一小包×××而遭惡警(加里·奧德曼飾)殺害全家的懲罰。",
    reading: "92",
    collection: "65",
    headImgSrc: "/images/post/ss.jpg",
    dataTime: "四天前",
    author: "Bill",
    detail: "里昂(讓·雷諾飾)是名孤獨的×××,受人雇傭。一天,鄰居家小姑娘馬蒂爾達(納塔麗·波特曼飾)敲開他的房門,要求在他那里暫避殺身之禍。原來鄰居家的主人是警方緝毒組的眼線,只因貪污了一小包×××而遭惡警(加里·奧德曼飾)殺害全家的懲罰。馬蒂爾達得到里昂的留救,幸免于難,并留在里昂那里。里昂教小女孩使槍,她教里昂法文,兩人關系日趨親密,相處融洽。女孩想著去×××,反倒被抓,里昂及時趕到,將女孩救回。混雜著哀怨情仇的正邪之戰漸次升級,更大的沖突在所難免…… ",
    postId: 4,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100000Zn0vS4fKKo8.m4a?fromtag=38",
      title: "沉默是金-張國榮",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000003at0mJ2YrR2H.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 04 2018",
    title: "阿甘正傳",
    imgSrc: "/images/post/ag.jpg",
    avatar: "/images/avatar/1.png",
    content: "阿甘(湯姆·漢克斯 飾)于二戰結束后不久出生在美國南方阿拉巴馬州一個閉塞的小鎮,他先天弱智,智商只有75,然而他的媽媽是一個性格堅強的女性,她常常鼓勵阿甘“傻人有傻福”,要他自強不息。",
    reading: "92",
    collection: "65",
    headImgSrc: "/images/post/ag.jpg",
    dataTime: "五天前",
    author: "Tony",
    detail: "阿甘(湯姆·漢克斯 飾)于二戰結束后不久出生在美國南方阿拉巴馬州一個閉塞的小鎮,他先天弱智,智商只有75,然而他的媽媽是一個性格堅強的女性,她常常鼓勵阿甘“傻人有傻福”,要他自強不息。阿甘像普通孩子一樣上學,并且認識了一生的朋友和至愛珍妮(羅賓·萊特·潘 飾),在珍妮和媽媽的愛護下,阿甘憑著上帝賜予的“飛毛腿”開始了一生不停的奔跑。阿甘成為橄欖球巨星、越戰英雄、乒乓球外交使者、億萬富翁,但是,他始終忘不了珍妮,幾次匆匆的相聚和離別,更是加深了阿甘的思念。有一天,阿甘收到珍妮的信,他們終于又要見面了……",
    postId: 5,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100002I8eGJ28BI17.m4a?fromtag=38",
      title: "朋友-譚詠麟",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000004eGsCN3SUheO.jpg?max_age=2592000"
    }
  },
]

// 設置一個數據出口
module.exports = {
  // 輸出的是一個Array對象
  postList: local_database,
}

運行效果:
播放:
第三個頁面:構建新聞詳情頁面

暫停:
第三個頁面:構建新聞詳情頁面


切換文章圖片

以上我們完成了簡單的音樂播放和暫停以及音樂圖標的切換,而且也說明了coverImg中引入的圖片只有在真機上,進入音樂界面后才能夠看到,但是我們也可以將coverImg引入的圖片顯示在文章詳情頁上,只需要做一個簡單的圖片切換即可:

<image src='{{isPlayingMusic ? postData.music.coverImg : postData.headImgSrc}}' class='head-iamge'></image>

運行效果:
播放:
第三個頁面:構建新聞詳情頁面

暫停:
第三個頁面:構建新聞詳情頁面


監聽播放事件完善音樂播放

在音樂播放的時候,可以看到會彈出來一個音樂播放的總控開關,我們點擊音樂圖標的時候能夠正常的切換圖片,但是點擊總控開關的時候不會切換圖片,這是因為我們只監聽了圖標上的事件,沒有監聽音樂播放、暫停的事件。所以我們還需要完善這點小細節,讓點擊總控開關的時候也能切換圖片,實現這一步需要使用到兩個API,onBackgroundAudioPlay以及onBackgroundAudioPause,前者用于監聽音樂播放,后者用于監聽音樂暫停。

在onLoad生命周期方法中增加以下代碼:

    var that = this;
    // 當音樂播放時將isPlayingMusic狀態改為true
    wx.onBackgroundAudioPlay(function(){
      that.setData({
        isPlayingMusic: true
      });
    });

    // 當音樂暫停時將isPlayingMusic狀態改為false
    wx.onBackgroundAudioPause(function(){
      that.setData({
        isPlayingMusic: false
      });
    })

加入以上代碼后就可以實現點擊總控開關也能切換圖片,而且以上代碼也體現出了數據綁定機制的好處,只需要修改數據集中相應數據的值即可,無需每次都去獲得節點對象后才能操作相應的數據的值。


應用程序生命周期

文章詳情頁中的音樂播放功能看起來基本是沒什么問題了,不過這也僅限于文章詳情這一個頁面內而已,如果我點擊了播放音樂,然后返回到上一級頁面,再點擊進入文章詳情頁的話,頁面的狀態就會是初始化時的狀態,這時音樂圖片就不會自動切換到播放狀態的圖片。這是因為我們的狀態代碼寫在js文件的Page對象里,會受到頁面生命周期的影響,當我們返回上一級頁面,再點擊進入文章詳情頁時,Page對象會被加載,頁面代碼就會被重新執行一遍,所以音樂圖標的狀態就會是初始時的狀態。

解決這個問題我們需要用到全局變量來保存狀態,全局變量不會受頁面生命周期的影響,而且在任何頁面中都可以獲取到全局變量的值。在小程序中全局變量需要寫在app.js文件中,該文件中的代碼需要寫在App對象里,就像我們的頁面代碼需要寫在Page中一樣,Page代表的是一個頁面,而App對象則是代表著整個應用程序,該對象的生命周期也就是應用程序的生命周期。以下是該對象的生命周期方法:

App({

  /**
   * 當小程序初始化完成時,會觸發 onLaunch(全局只觸發一次)
   */
  onLaunch: function () {

  },

  /**
   * 當小程序啟動,或從后臺進入前臺顯示,會觸發 onShow
   */
  onShow: function (options) {

  },

  /**
   * 當小程序從前臺進入后臺,會觸發 onHide
   */
  onHide: function () {

  },

  /**
   * 當小程序發生腳本錯誤,或者 api 調用失敗時,會觸發 onError 并帶上錯誤信息
   */
  onError: function (msg) {

  }
})

繼續完善音樂播放

以上我們簡單介紹了一下關于頁面狀態與全局變量以及應用程序生命周期,現在就可以使用全局變量來繼續完善音樂播放的功能了:

app.js代碼如下:

App({

  globalData:{
    g_isPlayingMusic:false
  },

});

post-detail.js代碼如下:

var postsData = require('../../../data/posts-data.js')
// 獲得全局的app對象
var app = getApp();

Page({
  data: {
    isPlayingMusic: false
  },

  onLoad: function (option) {

        ......以上代碼省略......

    // 當全局變量的狀態為播放時,也把頁面的狀態設置為teur 
    if (app.globalData.g_isPlayingMusic){
      this.setData({
        isPlayingMusic: true
      });
    }

    this.setMusicMonitor();
  },

  // 把監聽音樂的事件代碼提取出來
  setMusicMonitor:function(){
    var that = this;
    // 當音樂播放時將頁面以及全局狀態狀態改為true
    wx.onBackgroundAudioPlay(function () {
      that.setData({
        isPlayingMusic: true
      });
      app.globalData.g_isPlayingMusic = true;
    });

    // 當音樂暫停時將頁面以及全局狀態都改為false
    wx.onBackgroundAudioPause(function () {
      that.setData({
        isPlayingMusic: false
      });
      app.globalData.g_isPlayingMusic = false;
    });
  },

              ......以下代碼省略......

})

使用全局變量記錄狀態后,就不會出現之前的問題了,這時我們就可以在頁面加載時根據全局變量來設置頁面變量的狀態。


音樂播放最終章

除了以上的問題之外,我還找到了三個問題,第一個問題是當我們點擊音樂播放時,背景圖片會切換,但是我們只需要切換當前頁面的圖片,別的頁面不應該也跟著切換,而這個問題就是別的頁面也會跟著切換圖片,這個問題我們可以通過把頁面id存儲到全局變量里,根據id來決定是哪個頁面才會切換圖片,這樣就可以解決這個問題。

第二個問題是當我們關閉音樂播放器時,圖片不會切換,依舊停留在播放狀態,這個問題我們可以通過wx.onBackgroundAudioStop來解決。

第三個問題就是當我們在文章A里播放了音樂,然后到文章B上點擊音樂播放器的總控開關時,文章B的圖片也會跟著切換,解決這個問題稍微有點麻煩,因為要考慮到點擊圖標開關和點擊音樂播放器開關兩種情況,以及回到原本的頁面時還需切換圖片,我的解決思路是使用一個全局變量記錄上一個頁面,也就是原始頁面的id,通過這個id來決定切不切換圖片。

app.js文件內容如下:

App({

  globalData:{
    g_isPlayingMusic:false,
    g_currentMusicPostId:"",
    g_beforeMusicPostId: ""
  },

});

以下是修改后的post-detail.js文件內容:

var postsData = require('../../../data/posts-data.js')
// 獲得全局的app對象
var app = getApp();

Page({
  data: {
    isPlayingMusic: false
  },

  onLoad: function (option) {
    var postId = option.id; // 這里的id對應的是url參數上的id
    // 把postId設置到數據集里,這樣就能夠全局獲取
    this.data.currentPostId = postId;
    var postData = postsData.postList[postId];
    this.setData({
      postData
    });

    // 從緩存中獲取數據
    var postsCollected = wx.getStorageSync('posts_collected');
    // 判斷數據是否不為空
    if (postsCollected) {
      // 不為空就拿出與postId對應的下標值
      var postsCollected = postsCollected[postId];
      // 并將值更新到數據綁定里
      this.setData({
        collected: postsCollected
      });
    } else {
      // 如果為空就賦值一個空對象
      var postsCollected = {}
      // 并把與postId對應的下標中的值設置為false
      postsCollected[postId] = false;
      // 更新到緩存里
      wx.setStorageSync('posts_collected', postsCollected);
    }

    // 音樂在播放時改變狀態為true 
    if (app.globalData.g_isPlayingMusic && app.globalData.g_currentMusicPostId === postId){
      this.setData({
        isPlayingMusic: true
      });
    }

    this.setMusicMonitor();
  },

  // 把監聽音樂的事件代碼提取出來
  setMusicMonitor:function(){
    var that = this;

    // 監聽音樂播放
    wx.onBackgroundAudioPlay(function () {
      // 在原始頁面觸發播放事件時,切換頁面圖片,并且記錄當前文章的id
      if (app.globalData.g_beforeMusicPostId != "" && app.globalData.g_beforeMusicPostId === that.data.currentPostId){
        that.setData({
          isPlayingMusic: true
        });
        app.globalData.g_isPlayingMusic = true;
        app.globalData.g_currentMusicPostId = that.data.currentPostId;
        app.globalData.g_beforeMusicPostId = app.globalData.g_beforeMusicPostId;

      // 產生原始頁面時,或者圖標開關被點擊時,切換頁面圖片,并且記錄當前文章的id
      } else if (app.globalData.g_beforeMusicPostId == "" || that.data.isPlayingMusic){
        that.setData({
          isPlayingMusic: true
        });
        app.globalData.g_isPlayingMusic = true;
        app.globalData.g_currentMusicPostId = that.data.currentPostId;
        app.globalData.g_beforeMusicPostId = that.data.currentPostId;

      // 在非原始頁面觸發播放事件時,不切換該頁面的圖片
      } else{
        that.setData({
          isPlayingMusic: false
        });
        app.globalData.g_isPlayingMusic = true;
        app.globalData.g_currentMusicPostId = app.globalData.g_beforeMusicPostId;
      }
    });

    // 當音樂暫停時將頁面以及全局狀態都改為false,并且把當前文章的id清空
    wx.onBackgroundAudioPause(function () {
      that.setData({
        isPlayingMusic: false
      });
      app.globalData.g_isPlayingMusic = false;
      app.globalData.g_currentMusicPostId = "";
    });

    // 當音樂停止時將頁面以及全局狀態都改為false,并且把當前文章以及上一篇文章的id清空
    wx.onBackgroundAudioStop(function(){
      that.setData({
        isPlayingMusic: false
      });
      app.globalData.g_isPlayingMusic = false;
      app.globalData.g_currentMusicPostId = "";
      app.globalData.g_beforeMusicPostId = "";
    });
  },

  //點擊事件方法
  onCollectionTap: function (event) {
    // 獲取緩存數據
    var postsCollected = wx.getStorageSync('posts_collected');
    // 獲取postId
    var postCollected = postsCollected[this.data.currentPostId];
    // 收藏變成未收藏,未收藏變成收藏
    postCollected = !postCollected;
    postsCollected[this.data.currentPostId] = postCollected;

    // 自定義函數也需要使用this來訪問
    this.showModal(postsCollected, postCollected);
  },

  showModal: function (postsCollected, postCollected) {
    // 把this指代的Page對象先存儲起來
    var that = this;
    wx.showModal({
      title: '收藏',
      content: postCollected ? '是否收藏該文章?' : '是否取消收藏該文章?',
      showCancel: 'true',
      cancelText: '取消',
      cancelColor: '#333',
      confirmText: '確認',
      confirmColor: '#405f80',
      success: function (res) {
        if (res.confirm) {
          // 更新文章是否收藏的緩存值
          wx.setStorageSync('posts_collected', postsCollected);
          // 更新數據綁定變量,從而實現切換圖片
          that.setData({
            collected: postCollected
          });
          that.showToast(postsCollected, postCollected);
        }
      },
    });
  },

  showToast: function (postsCollected, postCollected) {
    wx.showToast({
      // 使用三元表達式來判斷狀態
      title: postCollected ? '收藏成功!' : '取消成功!',
      // 設置圖標停留的時間,單位是毫秒
      duration: 1000,
      // icon可以設置圖標,默認就是success
      icon: "success",
    });
  },

  onShareTap: function (event) {
    var itemList = [
      "分享給微信好友",
      "分享到朋友圈",
      "分享到QQ",
      "分享到微博",
    ]
    wx.showActionSheet({
      itemList: itemList,
      itemColor: "#405f80",
      success: function (res) {
        //res.cancel  用戶是否點擊了取消按鈕
        //res.tapIndex  數組元素的索引
        wx.showModal({
          title: itemList[res.tapIndex],
          content: '現在無法實現分享功能,什么時候能支持還未知',
        })
      },
    })
  },

  onMusicTap: function (event) {
    var currentPostId = this.data.currentPostId;
    var postData = postsData.postList[currentPostId];

    // 使用變量來記錄音樂的狀態
    var isPlayingMusic = this.data.isPlayingMusic;
    if (isPlayingMusic) {
      // 暫停音樂
      wx.pauseBackgroundAudio();
      this.setData({
        isPlayingMusic : false
      });

    } else {
      wx.playBackgroundAudio({
        // 流媒體文件的URL,目前支持的格式有 m4a, aac, mp3, wav
        dataUrl: postData.music.url,
        // 音樂標題
        title: postData.music.title,
        // 音樂封面URL
        coverImgUrl: postData.music.coverImg,
      });
      this.setData({
        isPlayingMusic: true
      });
    }
  },
})

以上就算是完成了一個基本的音樂播放效果,這個文章詳情頁面也就是算是完成了,雖然我感覺可能還存在一些問題,畢竟沒有完美的代碼,如果后續出現問題后再進行修復。我個人覺得開發項目應該先開發出一個能夠上線運行的原型,在運營的過程中再逐步去修復bug,迭代版本。


真機如何清除緩存與template的路徑問題

在小程序中的緩存數據都是沒有時效期的,不主動清除的話就會一直存在,在模擬器上我們可以點擊工具提供的清除緩存按鈕清除緩存數據:
第三個頁面:構建新聞詳情頁面

但是如果在真機上,則需要自己手動編寫一個清除緩存的按鈕,需要使用到wx.clearStorageSync()或wx.clearStorage()方法,前者是同步通清理本地數據緩存,后者則是異步清理本地數據緩存。當點擊這個按鈕的時候就能觸發一個點擊事件去執行這個清除緩存的方法。

template的路徑問題:

我們都知道template文件中的代碼目的是為了給其他頁面文件復用的,所以template代碼中的所包含的文件路徑不要寫相對路徑,寫絕對路徑比較好,因為如果文件A引用了template文件中的代碼,但是文件A和template文件并不是同一級的,那么這時候如果使用相對路徑就會有問題。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

南康市| 富源县| 婺源县| 兴化市| 运城市| 新沂市| 黄大仙区| 奉节县| 山阴县| 扎兰屯市| 三江| 东港市| 黔西县| 辉南县| 抚州市| 新河县| 自贡市| 会理县| 夏河县| 古浪县| 威宁| 桃园县| 万源市| 台南县| 南江县| 墨竹工卡县| 海伦市| 阜阳市| 丽水市| 金秀| 中方县| 英德市| 青冈县| 乐平市| 万州区| 吴江市| 常熟市| 大同市| 吴堡县| 莱阳市| 连平县|