微信小程序demo

前言

  閒來無事,筆者利用業餘時間學習了下微信小程序,而且作了一個demo,相似豆瓣的相關功能,本篇主要根據網頁的跳轉講解該demo的運行過程,重點在數據的傳輸而非css的講解,對於想要在儘可能短的時間掌握微信小程序經常使用用法的童鞋會比較有用css

準備工做

  申請帳號,獲取appId, 開發工具須要appId才能使用   html

 開發工具下載地址developers.weixin.qq.com/miniprogram…
git

正文

  源碼地址:github.com/qw870602/co…github

  使用工具打開項目,咱們會看到以下頁面數據庫

項目結構截圖json


data中的文件用來模擬數據庫,images顧名思義主要放圖片,pages包含全部的頁面,utils主要是工具類,app.js是給全局變量賦值的文件,app.wxss是設置全局的css樣式,咱們看到該文件對全局的<text>標籤和<input>標籤的樣式預設置了一些屬性,app.json是入口文件,換言之,咱們從app.json這個文件開始看起小程序

{
    "pages": [
    "pages/welcome/welcome",
    "pages/posts/post",
    "pages/movies/movies",
    "pages/movies/movie-detail/movie-detail",
    "pages/posts/post-detail/post-detail",
    "pages/movies/more-movie/more-movie"
],
    "window": {
    "navigationBarBackgroundColor": "#405f80"
},
    "tabBar": {
    "borderStyle": "white",
        "position": "bottom",
        "list": [
        {
            "pagePath": "pages/posts/post",
            "text": "閱讀",
            "iconPath": "images/tab/yuedu.png",
            "selectedIconPath": "images/tab/yuedu_hl.png"
        },
        {
            "pagePath": "pages/movies/movies",
            "text": "電影",
            "iconPath": "images/tab/dianying.png",
            "selectedIconPath": "images/tab/dianying_hl.png"
        }
    ]
}
}複製代碼

"pages":[] 包含了本demo全部的頁面路徑,其中最上面的路徑就是咱們打開項目看到的歡迎頁微信小程序

window中的navigationBarBackgroundColor是導航欄背景顏色,這個型號表明深藍色,這裏並不在首頁顯示,下面的tarBar是設置底部tab欄的屬性api

小程序首先找到app.json,而後去找首頁welcome, welcome頁面的主體由如下4個文件組成數組


wxml能夠類比爲html, js主要用來捕捉事件作頁面跳轉,wxss相似css ,json主要用來作一些配置

咱們看一下wxml的內容

<view class="container">
    <image class="avatar" src="/images/avatar/1.png"></image>
    <text class="motto">Hello, 七月</text>
    <view class="journey-container" bindtap="onTap">
      <text class="journey">開啓小程序之旅</text>
    </view>
</view>複製代碼

全部內容包裹在container中,在wxss中設置了背景色爲淺藍色,在json中設置了導航欄的顏色也爲淺藍色,故咱們看到整個背景是淺藍色,至於圖片和文字的位置,樣式的css實現,讀者可自行研究,點擊 「開啓小程序之旅」 ,經過bindTap組件觸發onTab函數,再調用wx.switchTab跳轉到post頁面

頁面效果


post.wxml

<import src="post-item/post-item-template.wxml" />
<view>
    <swiper catchtap="onSwiperTap" vertical="{{false}}" indicator-dots="true" autoplay="true" interval="5000">
        <swiper-item>
            <image id="7" src="/images/wx.png" data-postId="3"></image>
        </swiper-item>
        <swiper-item>
            <image src="/images/vr.png" data-postId="4"></image>
        </swiper-item>
        <swiper-item>
            <image src="/images/iqiyi.png" data-postId="5"></image>
        </swiper-item>
    </swiper>
    <block wx:for="{{postList}}" wx:for-item="item" wx:for-index="idx">
        <!--//template-->
        <view catchtap="onPostTap" data-postId="{{item.postId}}">
            <template is="postItem" data="{{...item}}"/>
        </view>
    </block>
</view>複製代碼

最外層被view包裹,第一部分的swiper是輪播圖組件,下面的block其實就是獲取最上面import的集合數據,底層的tab欄其實就是以前app.json中設置的,由於咱們跳轉的是post, 而後閱讀的pagePath設置的就是post,因此底層 「閱讀」 tab欄就是被選中的狀態,輪播圖的組件屬性再也不介紹,可參照api文檔

點擊輪播圖中的任意一張


其流程是經過catchTap組件捕捉到點擊事件,而後調用post.js的onSwiperTap方法跳轉到post-detail頁面並順帶將被點擊頁面的id傳過去

post-detail.wxml

<!--先靜後動,先樣式再數據-->
<view class="container">
    <image class="head-image" src="{{isPlayingMusic?postData.music.coverImg:postData.headImgSrc}}"></image>
    <image catchtap="onMusicTap" class="audio" src="{{isPlayingMusic? '/images/music/music-stop.png': '/images/music/music-start.png'}}"></image>
    <view class="author-date">
        <image class="avatar" src="{{postData.avatar}}"></image>
        <text class="author">{{postData.author}}</text>
        <text class="const-text">發表於</text>
        <text class="date">{{postData.dateTime}}</text>
    </view>
    <text class="title">{{postData.title}}</text>
    <view class="tool">
        <view class="circle-img">
            <image wx:if="{{collected}}" catchtap="onColletionTap"  src="/images/icon/collection.png"></image>
            <image wx:else catchtap="onColletionTap" src="/images/icon/collection-anti.png"></image>
            <image catchtap="onShareTap"  class="share-img" src="/images/icon/share.png"></image>
        </view>
        <view class="horizon"></view>
    </view>
    <text class="detail">{{postData.detail}}</text>
</view>複製代碼

咱們看到wxml中的數據不少都是經過 {{  }} 動態獲取的,咱們知道傳了1個id值過來,那麼是怎麼根據id值獲取詳情信息的呢?答案在post-detail.js中

post-detail.js ,有點長,可跳過,須要看時再回頭查

var postsData = require('../../../data/posts-data.js')
var app = getApp();
Page({
    data: {
        isPlayingMusic: false
    },
    onLoad: function (option) {
        var postId = option.id;
        this.data.currentPostId = postId;
        var postData = postsData.postList[postId];
        this.setData({
            postData: postData
        })

        var postsCollected = wx.getStorageSync('posts_collected')
        if (postsCollected) {
            var postCollected = postsCollected[postId]
            if (postCollected){
                this.setData({
                    collected: postCollected
                })
            }
        }
        else {
            var postsCollected = {};
            postsCollected[postId] = false;
            wx.setStorageSync('posts_collected', postsCollected);
        }

        if (app.globalData.g_isPlayingMusic && app.globalData.g_currentMusicPostId
            === postId) {
            this.setData({
                isPlayingMusic: true
            })
        }
        this.setMusicMonitor();
    },

    setMusicMonitor: function () {
        //點擊播放圖標和總控開關都會觸發這個函數
        var that = this;
        wx.onBackgroundAudioPlay(function (event) {
            var pages = getCurrentPages();
            var currentPage = pages[pages.length - 1];
            if (currentPage.data.currentPostId === that.data.currentPostId) {
                // 打開多個post-detail頁面後,每一個頁面不會關閉,只會隱藏。經過頁面棧拿到到
                // 當前頁面的postid,只處理當前頁面的音樂播放。
                if (app.globalData.g_currentMusicPostId == that.data.currentPostId) {
                    // 播放當前頁面音樂才改變圖標
                    that.setData({
                        isPlayingMusic: true
                    })
                }
                // if(app.globalData.g_currentMusicPostId == that.data.currentPostId )
                // app.globalData.g_currentMusicPostId = that.data.currentPostId;
            }
            app.globalData.g_isPlayingMusic = true;

        });
        wx.onBackgroundAudioPause(function () {
            var pages = getCurrentPages();
            var currentPage = pages[pages.length - 1];
            if (currentPage.data.currentPostId === that.data.currentPostId) {
                if (app.globalData.g_currentMusicPostId == that.data.currentPostId) {
                    that.setData({
                        isPlayingMusic: false
                    })
                }
            }
            app.globalData.g_isPlayingMusic = false;
            // app.globalData.g_currentMusicPostId = null;
        });
        wx.onBackgroundAudioStop(function () {
            that.setData({
                isPlayingMusic: false
            })
            app.globalData.g_isPlayingMusic = false;
            // app.globalData.g_currentMusicPostId = null;
        });
    },

    onColletionTap: function (event) {
        // this.getPostsCollectedSyc();
        this.getPostsCollectedAsy();
    },

    getPostsCollectedAsy: function () {
        var that = this;
        wx.getStorage({
            key: "posts_collected",
            success: function (res) {
                var postsCollected = res.data;
                var postCollected = postsCollected[that.data.currentPostId];
                // 收藏變成未收藏,未收藏變成收藏
                postCollected = !postCollected;
                postsCollected[that.data.currentPostId] = postCollected;
                that.showToast(postsCollected, postCollected);
            }
        })
    },

    getPostsCollectedSyc: function () {
        var postsCollected = wx.getStorageSync('posts_collected');
        var postCollected = postsCollected[this.data.currentPostId];
        // 收藏變成未收藏,未收藏變成收藏
        postCollected = !postCollected;
        postsCollected[this.data.currentPostId] = postCollected;
        this.showToast(postsCollected, postCollected);
    },

    showModal: function (postsCollected, postCollected) {
        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
                    })
                }
            }
        })
    },

    showToast: function (postsCollected, postCollected) {
        // 更新文章是否的緩存值
        wx.setStorageSync('posts_collected', postsCollected);
        // 更新數據綁定變量,從而實現切換圖片
        this.setData({
            collected: postCollected
        })
        wx.showToast({
            title: postCollected ? "收藏成功" : "取消成功",
            duration: 1000,
            icon: "success"
        })
    },

    onShareTap: function (event) {
        var itemList = [
            "分享給微信好友",
            "分享到朋友圈",
            "分享到QQ",
            "分享到微博"
        ];
        wx.showActionSheet({
            itemList: itemList,
            itemColor: "#405f80",
            success: function (res) {
                // res.cancel 用戶是否是點擊了取消按鈕
                // res.tapIndex 數組元素的序號,從0開始
                wx.showModal({
                    title: "用戶 " + itemList[res.tapIndex],
                    content: "用戶是否取消?" + res.cancel + "如今沒法實現分享功能,何時能支持呢"
                })
            }
        })
    },

    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
            })
            // app.globalData.g_currentMusicPostId = null;
            app.globalData.g_isPlayingMusic = false;
        }
        else {
            wx.playBackgroundAudio({
                dataUrl: postData.music.url,
                title: postData.music.title,
                coverImgUrl: postData.music.coverImg,
            })
            this.setData({
                isPlayingMusic: true
            })
            app.globalData.g_currentMusicPostId = this.data.currentPostId;
            app.globalData.g_isPlayingMusic = true;
        }
    },

    /*
     * 定義頁面分享函數
     */
    onShareAppMessage: function (event) {
        return {
            title: '離思五首·其四',
            desc: '曾經滄海難爲水,除卻巫山不是雲',
            path: '/pages/posts/post-detail/post-detail?id=0'
        }
    }

})複製代碼

實際上這裏執行的onload函數,經過傳進去的id獲取到對應的對象放在postData中

下面的postCollected部分主要用來控制收藏按鈕的顯示,若是初始狀態爲未收藏,那麼就不對collected賦值,wxml中collected若是沒有值的話會被認爲是false,那麼按鈕就顯示爲未收藏的狀態

再下面的app.globalData.g_isPlayingMusic && app.globalData.g_currentMusicPostId === postId  顯然是不成立的,由於app.js中設置了globalData.g_isPlayingMusic出事狀態爲false。雖然會執行setMusicMonitor函數,可是執行進去以後並不會進入到設置isPlayingMusic這個變量值的模塊裏面去,因此頁面是沒有播放音樂的

head-image 是背景圖片,隨着是否播放音樂變化,audio是背景圖片上的播放圖標

咱們點擊一下播放按鈕,看看是什麼效果


咱們發現頭部的背景圖片變成了譚詠麟的圖片,中間的播放按鈕變成了正在播放的狀態,屏幕正中間彈出了1個音樂播放器,內部執行了哪些程序呢?

實際上是先被catchTap組件捕獲,而後調用onMusicTap方法,執行了這部分代碼

else {
   wx.playBackgroundAudio({
   dataUrl: postData.music.url,
   title: postData.music.title,
   coverImgUrl: postData.music.coverImg,
  })
   this.setData({
     isPlayingMusic: true
  })
   app.globalData.g_currentMusicPostId = this.data.currentPostId;
   app.globalData.g_isPlayingMusic = true;
}

而後再次跳轉到這個頁面

再次點擊播放按鈕,暫停播放


再次觸發onMusicTap方法,實際上主要執行了這部分代碼

if (isPlayingMusic) {
   wx.pauseBackgroundAudio();
   this.setData({
   isPlayingMusic: false
  })
   // app.globalData.g_currentMusicPostId = null;
   app.globalData.g_isPlayingMusic = false;
}

咱們看一下收藏功能的實現,點擊收藏

首先彈出一個提示框,提示收藏成功,而後紅框部分由淺色變爲深藍色標識已經收藏,每次點擊會觸發onColletionTap方法,該方法每次會將屬性collected的值取反,而且根據postCollected的值提示一段文字

再看一下分享功能的實現

點擊 「分享」,效果如圖


觸發onShareTap函數

onShareTap: function (event) {
    var itemList = [
        "分享給微信好友",
        "分享到朋友圈",
        "分享到QQ",
        "分享到微博"
    ];
    wx.showActionSheet({
        itemList: itemList,
        itemColor: "#405f80",
        success: function (res) {
            // res.cancel 用戶是否是點擊了取消按鈕
            // res.tapIndex 數組元素的序號,從0開始
            wx.showModal({
                title: "用戶 " + itemList[res.tapIndex],
                content: "用戶是否取消?" + res.cancel + "如今沒法實現分享功能,何時能支持呢"
            })
        }
    })
}複製代碼

點擊 「分享到朋友圈」


提示框展現的內容其實是wx.showModal的內容,由於咱們並無真的實現分享功能,因此這裏點擊 「取消」 或 「肯定」 都會回到原界面

點擊左上角的回退箭頭回到主界面


點擊 「正是蝦肥蟹壯時」,效果以下


咱們發現和點擊頭部輪播圖的效果是同樣的,這裏又是怎麼實現的呢?

在post.wxml中有這一部分

<block wx:for="{{postList}}" wx:for-item="item" wx:for-index="idx">
    <!--//template-->
    <view catchtap="onPostTap" data-postId="{{item.postId}}">
    <template is="postItem" data="{{...item}}"/>
    </view>
</block>複製代碼

實際上這裏的點擊觸發的的是onPostTab函數,和以前的onSwiperTap是一個效果

onPostTap: function (event) {
    var postId = event.currentTarget.dataset.postid;
    // console.log("on post id is" + postId);
    wx.navigateTo({
        url: "post-detail/post-detail?id=" + postId
    })
}複製代碼

<template>實際上是微信定義的一個模板組件,模板的樣式由頂部的導入語句

<import src="post-item/post-item-template.wxml" />  就能夠推判定義在post-item/post-item-template.wxml 這個文件中

咱們再回到主界面,而後點擊底部tab欄的 「電影「

咱們看一下movies.wxml

<import src="movie-list/movie-list-template.wxml" />
<import src="movie-grid/movie-grid-template.wxml" />
<view class="search">
    <icon type="search" class="search-img" size="13" color="#405f80"></icon>
    <input type="text" placeholder="血戰鋼鋸嶺、你的名字"
           placeholder-class="placeholder" bindfocus="onBindFocus"
           bindconfirm="onBindConfirm"/>
    <image wx:if="{{searchPanelShow}}" src="/images/icon/xx.png" class="xx-img" catchtap="onCancelImgTap"></image>
</view>
<view class="container" wx:if="{{containerShow}}">
    <view class="movies-template">
        <template is="movieListTemplate" data="{{...inTheaters}}" />
    </view>

    <view class="movies-template">
        <template is="movieListTemplate" data="{{...comingSoon}}" />
    </view>
    <view class="movies-template">
        <template is="movieListTemplate" data="{{...top250}}"/>
    </view>
</view>

<view class="search-panel" wx:if="{{searchPanelShow}}">
    <template is="movieGridTemplate" data="{{...searchResult}}"/>
</view>複製代碼

一共3大部分,搜索欄search,主體內容container,其中包括正在上映,即將上映,top250三大內容,搜索面板search-panel。觀察一下movies.js,看看傳了哪些值進來

data: {
    inTheaters: {},
    comingSoon: {},
    top250: {},
    searchResult: {},
    containerShow: true,
    searchPanelShow: false,
},

onLoad: function (event) {
    var inTheatersUrl = app.globalData.doubanBase +
        "/v2/movie/in_theaters" + "?start=0&count=3";
    var comingSoonUrl = app.globalData.doubanBase +
        "/v2/movie/coming_soon" + "?start=0&count=3";
    var top250Url = app.globalData.doubanBase +
        "/v2/movie/top250" + "?start=0&count=3";

    this.getMovieListData(inTheatersUrl, "inTheaters", "正在熱映");
    this.getMovieListData(comingSoonUrl, "comingSoon", "即將上映");
    this.getMovieListData(top250Url, "top250", "豆瓣Top250");
}複製代碼

從這裏看出searchPanelShow爲false,因此第三部分是不顯示的,因而就有了咱們看到的效果

點擊搜索欄,輸入 」肖申克「 ,而後點擊搜索


咱們看一下點擊搜索時發生了什麼

onBindFocus: function (event) {
    this.setData({
        containerShow: false,
        searchPanelShow: true
    })

},

onBindConfirm: function (event) {
    var text = event.detail.value;
    var searchUrl = app.globalData.doubanBase + "/v2/movie/search?q=" + text;
    this.getMovieListData(searchUrl, "searchResult", "");
}複製代碼

主題內容container再也不顯示,搜索結果數據放入searchResult,而且以serach-panel的模板顯示出來

回到電影主界面,點擊正在熱映的 」更多「


執行代碼

onMoreTap: function (event) {
    var category = event.currentTarget.dataset.category;
    wx.navigateTo({
        url: "more-movie/more-movie?category=" + category
    })
}複製代碼

跳轉到了 more-movie頁面,再次執行more-movie.js

data: {
    movies: {},
    navigateTitle: "",
        requestUrl: "",
        totalCount: 0,
        isEmpty: true,
},
onLoad: function (options) {
    var category = options.category;
    this.data.navigateTitle = category;
    var dataUrl = "";
    switch (category) {
        case "正在熱映":
            dataUrl = app.globalData.doubanBase +
                "/v2/movie/in_theaters";
            break;
        case "即將上映":
            dataUrl = app.globalData.doubanBase +
                "/v2/movie/coming_soon";
            break;
        case "豆瓣Top250":
            dataUrl = app.globalData.doubanBase + "/v2/movie/top250";
            break;
    }
    wx.setNavigationBarTitle({
        title: this.data.navigateTitle
    })
    this.data.requestUrl = dataUrl;
    util.http(dataUrl, this.processDoubanData)
}複製代碼

這裏至關於又去豆瓣從新查了一下

回到電影主界面,咱們隨意點擊一部影片,好比 」後來的咱們「


從movie-template.wxml中咱們發現點擊影片後會執行onMovieTap方法,這個方法在movies.js中

onMovieTap:function(event){
    var movieId = event.currentTarget.dataset.movieid;
    wx.navigateTo({
        url: "movie-detail/movie-detail?id="+movieId
    })
}複製代碼

跳轉到movie-detail.wxml

點擊右上角的電影圖片,有1個放大的效果


執行代碼

/*查看圖片*/
viewMoviePostImg: function (e) {
    var src = e.currentTarget.dataset.src;
    wx.previewImage({
        current: src, // 當前顯示圖片的http連接
        urls: [src] // 須要預覽的圖片http連接列表
    })
}複製代碼

咱們看到其實這個大圖是從豆瓣拿的

相關文章
相關標籤/搜索