1
如果觉得事情太复杂无从下手,就分成许多许多个小步进行好了 ---尼古斯拉

下载与安装

小程序下载地址

安装过程非常简单直接下一步就行了。

核心文件解释

app.json

app.json 文件如下:

 {
      "pages":[
        "pages/index/index",
        "pages/logs/logs"

      ],
      "window":{
        "backgroundTextStyle":"light",
        "navigationBarBackgroundColor": "#fff",
        "navigationBarTitleText": "WeChat",
        "navigationBarTextStyle":"black"
      },
      "tabBar": {
        "color": "#858585",
        "selectedColor": "#000000",
        "backgroundColor": "#ffffff",
        "list": [ 
          {
            "pagePath": "pages/index/index",
            "text": "首页",
            "iconPath": "/img/tab_home.png",
            "selectedIconPath": "/img/tab_home-active.png"
          },
          {
            "pagePath": "pages/logs/logs",
            "text": "日志",
            "iconPath": "/img/tab_category.png",
            "selectedIconPath": "/img/tab_category-active.png"
          }
          ]
        }
    }
  • pages 是整个小程序的页面配置路径,只有在这里配置了的页面路径才能生效使用;
  • window 是配置整个小程序窗口风格的;
  • tabBar 是配置底部两个菜单的;

组件化开发搜索栏

先看效果:

clipboard.png

点击
clipboard.png

发生了什么?我们发现首页有一个搜索栏,其实这相当于一个导航的图标,点击以后才跳转到了真正的搜索页面。由于他们的样式是一样的,我们打算要开发一个组件,然后在各自的页面引用这个组件,就可以达到代码复用的目的。这个很重要,因为小程序主打的就是"轻型应用",整个程序不超过2M,所以代码能省则省。两个页面除了样式大体差不多,但是又有不一样的地方,这就涉及了逻辑判断,如何做呢?且看我慢慢道来。

开发searchbar组件备用

首页有了,导航的这个图标得我们自己开发吧,如何做呢?
点击小加号->新建目录->右键新建component,填上值就可以了。
小加号在哪呢?

clipboard.png
然后就是这个组件内容的开发啦,这里只贴出核心部分,样式什么的的我稍后上传到github,自己看。

<view class="searchbar">
  <navigator url='/pages/search/search' class='search-navigator'></navigator>
</view>

我们使用<navigator>标签告诉小程序跳转到url所指的页面组件做好了,接下来我们应用它。

首页应用searchbar组件

index.json文件中告诉小程序我们要使用这个组件

 {
  "usingComponents": {
    "searchbar": "/components/searchbar/searchbar"
  }
}

接下来打标签直接使用,为了区分使用view作个标记

<searchbar></searchbar>
<view>这是首页</view>

然后我们还需要新建一个search.wxml页面及其组件,如何新建呢?
还记得之前我们说过的app.json文件吗,这个文件有个pages属性管理所有的页面,现在我们增加一条pages/search/search保存刷新,页面就自动建好了。search.wxml引用组件的过程和首页相同,这里不过多叙述。

  "pages":[
    "pages/index/index",
    "pages/search/search",
    "pages/logs/logs"
  ]

最后我们要实现的是在首页只显示导航的图标,在搜索栏显示一个输入框,如何做呢?

找到searchbar.wxml页面,多加一个view、它里面是一个输入框,输入框样式什么的自己看,不是本文的重点。

<view class="searchbar">
  <navigator url='/pages/search/search' class='search-navigator'></navigator>
  <view class="search-input-group">
    <input class='search-input' placeholder='搜索' bindinput='onInputEvent'></input>
  </view>
</view>

接下来我们做的事情就是,如果是首页引用这个组件就显示图标,搜索页引用就显示输入框。

找到searchbar.js文件,在组件的属性列表properties这一项新增一个属性isnavigator,它的类型是 Boolean,初始值为false

 properties: {
    isnavigator: {
      type: Boolean,
      value: false
    }
  }

接下来在searchbar.wxml应用这个属性

<view class="searchbar">
  <navigator wx:if="{{isnavigator}}" url='/pages/search/search' class='search-navigator'></navigator>
  <view wx:else class="search-input-group">
    <input class='search-input' placeholder='搜索' bindinput='onInputEvent'></input>
  </view>
</view>

表示属性值为ture的时候就显示图标,false的时候就显示输入框。

接下来我们要去index.wxml改下插件的属性值

<searchbar isnavigator="{{true}}"></searchbar>

由于默认值为false、search.wxml就不用改了。这样,首页加载就显示图标,搜索页加载就显示输入框。别看简单,初次开发思路不清晰也挺费劲,容易乱。就这样我们就学会了组件化思想和使用逻辑判断,是不是很厉害呢。

首页布局与数据获取

完成效果如下

clipboard.png

分析:首页的主要部分为红色大框部分,其中包括了标题、主体、星星三个小框框,只要把这个大框开发好了,其余的都是这个大框的重复。我们打算把这个大框开发成一个独立的组件,由于星星在后面其他地方有复用,星星这个部分我们也开发成一个独立的组件。

首页组件的开发
在components目录下新建目录indexmodule,再新建component
接下进行indexmodule.wxml页面的编写。

标题和滚动条布局

<view class='module-group'>
  <view class='module-top'>
    <view class='module-title'>电影</view>
    <navigator class='module-more'>更多</navigator>
  </view>
  <scroll-view class='module-scroll-view'>
    <navigator class='item-navigator' url="">
      <view class='item-group'>
        <view class='thumbnail-group'>
          <image class='thumbnail' src='https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2544987866.webp'></image>
        </view>
        <view class='item-title'>阿丽塔</view>
      </view>
    </navigator>
  </scroll-view>
</view>

在`index.json告诉小程序我们要使用这个组件

{
  "usingComponents": {
    "searchbar": "/components/searchbar/searchbar",
    "indexmodule": "/components/indexmodule/indexmodule"
  }
}

index.wxml引入

<indexmodule></indexmodule>

效果如下:

clipboard.png
页面包括了标题和滚动条,还差星星,下面我们开发星星组件,并在这个页面引入。

星星的布局

代码如下:

<view class='rate-group'>
  <image  wx:for="{{[1,2,3]}}" src="/images/rate_light.png"></image>
  <image  src='/images/rate_half.png'></image>
  <image  src='/images/rate_gray.png'></image>
  <text>7.0</text>
</view>

接下来在indexmodule.json告诉小程序我们要引用这个组件。

{
  "component": true,
  "usingComponents": {
    "stars": "/components/stars/stars"}
}

最后在indexmodule.json直接引用就好了

<navigator class='item-navigator' url="">
      <view class='item-group'>
        <view class='thumbnail-group'>
          <image class='thumbnail' src='https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2544987866.webp'></image>
        </view>
        <view class='item-title'>阿丽塔</view>
      </view>
      <stars></stars>
</navigator>

效果如下:

clipboard.png

根据评分动态渲染星星

 <stars rate="9"></stars>

打开stars.js文件,添加一个属性rate,类型为Number,默认值为0

properties: {
    rate: {
      type: Number,
      value: 0
    }
  }

处理逻辑:

lifetimes: {
    attached: function () {
      var that = this;
      var rate = that.properties.rate;
      var intRate = parseInt(rate);
      var light = parseInt(intRate / 2);
      var half = intRate % 2;
      var gray = 5 - light - half;
      var lights = [];
      var halfs = [];
      var grays = [];
      for (var index = 1; index <= light; index++) {
        lights.push(index);
      }
      for (var index = 1; index <= half; index++) {
        halfs.push(index);
      }
      for (var index = 1; index <= gray; index++) {
        grays.push(index);
      }
      var ratetext = rate && rate > 0 ? rate.toFixed(1) : "未评分"
      that.setData({
        lights: lights,
        halfs: halfs,
        grays: grays,
        ratetext: ratetext
      });
    }
  }

动态渲染出来:

  <image  wx:for="{{lights}}" src="/images/rate_light.png"></image>
  <image  wx:for="{{halfs}}"src='/images/rate_half.png'></image>
  <image  wx:for="{{grays}}"src='/images/rate_gray.png'></image>

动态数据加载和渲染

index.js中使用wx.request请求数据:

 onLoad: function () {
   var that=this;
   wx.request({
     url: 'https://m.douban.com/rexxar/api/v2/subject_collection/movie_showing/items?count=7',
     success: function (res) {
       var movies = res.data.subject_collection_items;
       that.setData({
         movies: movies
         });
       console.log(movies);
     }
   })
  }

indexmodule.js添加属性,它的类型为数组类型:

items:{
      type:Array,
      value:[]
    }

index.wxml给这个属性赋值:

<indexmodule  items="{{movies}}"></indexmodule>

然后在indexmoduel.wxml就可以使用啦:

 <navigator class='item-navigator' url="" wx:for="{{items}}" wx:key="{{item.title}}">
      <view class='item-group'>
        <view class='thumbnail-group'>
          <image class='thumbnail' src='{{item.cover.url}}'></image>
        </view>
        <view class='item-title'>{{item.title}}</view>
      </view>
      <stars rate="{{item.rating.value}}"></stars>
</navigator>

效果如下:

clipboard.png

wx:key

框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

结论:for 循环的时候必须要有wx:key以保持自己的特征和状态,key 的值可以是字符串或者数字,而且需要在列表中是唯一的。在写的时候,直接写这个 property 的名字就可以了,如果循环中的 item 本身,比如说循环的是一个数组,使用*this指代本身就可以了。

列表页以及网络请求重构

如果在个点逻辑转不过来、或是效果没出来,先放下好了,回过头来再看突然就明白了 --尼古斯拉

点击更多,效果如下:
分析:由于列表中每一项和首页滑动栏的每一项是一样的,因此我们抽取出来,单独作为一个itemview组件。然后在首页和列表页都可以调用,达到复用的目的。

itemview组件

页面布局很简单,把之前在indexmodule.wxml写过的复制过来就行了

<navigator class='item-navigator' url="">
  <view class='item-group'>
    <view class='thumbnail-group'>
      <image class='thumbnail' src='{{item.cover.url}}'></image>
    </view>
    <view class='item-title'>{{item.title}}</view>
    <stars rate="{{item.rating.value}}"></stars>
  </view>
</navigator>

记得在itemview.json告诉小程序我们要使用星星组件哦

 "usingComponents": {
    "stars": "/components/stars/stars"
  }

最后在indexmodule.wxml使用这个组件

"usingComponents": {
   "itemview": "/components/itemview/itemview"
  }
<scroll-view class='module-scroll-view' scroll-x="{{true}}">
   <itemview wx:for="{{items}}" wx:key="{{item.title}}" item="{{item}}"></itemview>
</scroll-view>

列表页

<searchbar isnavigator="{{true}}"></searchbar>
<view class='container'>
  <itemview wx:for="{{items}}" wx:key="{{item.title}}" item="{{item}}"></itemview>
</view>
"usingComponents": {
    "searchbar": "/components/searchbar/searchbar",
    "itemview": "/components/itemview/itemview"
 }

页面构成非常简单,不过多叙述。

网络请求重构

我们要做的事情很简单,把所有的网络请求放在一个文件统一完成,然后根据不同的参数在不同的页面完成渲染。

1、在utils目录新建urls.js文件统一存放所以url,记得导出。

const globalUrls = {
  movieList: "https://m.douban.com/rexxar/api/v2/subject_collection/movie_showing/items",
  tvList: "https://m.douban.com/rexxar/api/v2/subject_collection/tv_hot/items",
  showList: "https://m.douban.com/rexxar/api/v2/subject_collection/tv_variety_show/items"
}
export { globalUrls }

在utils目录新建network.js完成所有的请求,需要导入urls.jsglobalUrls,完成业务处理后记得导出。

import { globalUrls } from "urls.js";
const network = {
  // 获取电影列表
  getMovieList: function (params) {
    params.url = globalUrls.movieList;
    this.getItemList(params);
  },
  //获取电视剧列表
  getTVList: function (params) {
    params.url = globalUrls.tvList;
    this.getItemList(params);
  },
  // 获取综艺列表
  getShowList: function (params) {
    params.url = globalUrls.showList;
    this.getItemList(params);
  }, 
  getItemList: function (params) {  
    var count = params.count ? params.count : 7;
    wx.request({
      url: params.url,
      data: {
        count: count
      },
      success: function (res) {
        var items = res.data.subject_collection_items;
        if (params && params.success) {
          params.success(items);
        }
      }
    });
  }
}
export { network }

定义了四个方法,其中getItemList是干活的方法,其他的根据不同的url来引用这个方法,便可以获取不同的数据。

首页引用数据:
首页引用数据是在index.js中的onLoad中写代码,记得要引用network.jsnetwork

import { network } from "../../utils/network.js";
//获取应用实例
Page({
  data: {  
  },
  onLoad: function (options) {
    var that = this;
    // 电影
    network.getMovieList({
      success: function (movies) {
        that.setData({
          movies: movies
        });
      }
    });
    // 电视剧
    network.getTVList({
      success: function (tvs) {
        that.setData({
          tvs: tvs
        });
      }
    });

    // 综艺
    network.getShowList({
      success: function (shows) {
        that.setData({
          shows: shows
        });
      }
    });
  }
})

数据渲染很简单,参照前面就行了,就是把变量的值传过去而已,不罗嗦。

列表页引用数据:

<!-- 电影 -->
<indexmodule title="电影" items="{{movies}}" moreurl="/pages/list/list?type=movie"></indexmodule>

<!-- 电视剧 -->
<indexmodule title="电视剧" items="{{tvs}}" moreurl="/pages/list/list?type=tv" ></indexmodule>

<!-- 综艺 -->
<indexmodule title="综艺" items="{{shows}}" moreurl="/pages/list/list?type=show"></indexmodule>

我们在首页index.wxmlmoreurl属性赋值时添加了一个一个参数type作为区分,稍候既可以在请求数据的list.js拿到type的值,然后就可以根据type的值不同从而请求不同的数据。

list.js请求数据的代码如下:

onLoad: function (options) {
    var that = this;
    var type = options.type;
    var title = "";
    wx.showLoading({
      title: '正在加载中...',
    })
    if (type === "movie") {
      // 请求电影的数据
      network.getMovieList({
        success: function (items) {
          that.setData({
            items: items
          });
          wx.hideLoading();
        },
        count: 1000
      });
      title = "电影";
    } else if (type === 'tv') {
      // 请求电视剧的数据
      network.getTVList({
        success: function (items) {
          that.setData({
            items: items
          });
          wx.hideLoading();
        },
        count: 1000
      });
      title = "电视剧";
    } else {
      // 请求综艺的数据
      network.getShowList({
        success: function (items) {
          that.setData({
            items: items
          });
          wx.hideLoading();
        },
        count: 1000
      });
      title = "综艺";
    }
    wx.setNavigationBarTitle({
      title: title,
    })
  }

记得要引入network,怎么引不用啰嗦了吧。

这样,列表页以及网络重构就全部完成了,刚开始做可能有些陌生,没关系,慢慢来。

小插曲:

clipboard.png

点开更多发现怎么这样子的?
查资料发现是flex-wrap:wrap 控制水平折行排列的,可我也写了呀,哪肯定是什么地方影响了。
后来发现

clipboard.png
这里也定义了一个container样式,删掉就好了。这个教训告诉我们知识一定要全面呀,知识全面思路才清晰。

详情页布局以及数据加载


Nirvana
32 声望5 粉丝

整个体系复杂对我而言又陌生,每次学习对自己的脑力与知识体系都是一个巨大的挑战,也需要克服巨大的惰性;巨大的挑战同时也意味着巨大的诱惑。意味着我搞懂了,就能超越平凡的大多数,能力又上升了一个台阶。一...