如果觉得事情太复杂无从下手,就分成许多许多个小步进行好了 ---尼古斯拉
下载与安装
安装过程非常简单直接下一步就行了。
核心文件解释
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 是配置底部两个菜单的;
组件化开发搜索栏
先看效果:
点击
发生了什么?我们发现首页有一个搜索栏,其实这相当于一个导航的图标,点击以后才跳转到了真正的搜索页面。由于他们的样式是一样的,我们打算要开发一个组件,然后在各自的页面引用这个组件,就可以达到代码复用的目的。这个很重要,因为小程序主打的就是"轻型应用",整个程序不超过2M,所以代码能省则省。两个页面除了样式大体差不多,但是又有不一样的地方,这就涉及了逻辑判断,如何做呢?且看我慢慢道来。
开发searchbar组件备用
首页有了,导航的这个图标得我们自己开发吧,如何做呢?
点击小加号->新建目录->右键新建component,填上值就可以了。
小加号在哪呢?
然后就是这个组件内容的开发啦,这里只贴出核心部分,样式什么的的我稍后上传到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就不用改了。这样,首页加载就显示图标,搜索页加载就显示输入框。别看简单,初次开发思路不清晰也挺费劲,容易乱。就这样我们就学会了组件化思想和使用逻辑判断,是不是很厉害呢。
首页布局与数据获取
完成效果如下
分析:首页的主要部分为红色大框部分,其中包括了标题、主体、星星三个小框框,只要把这个大框开发好了,其余的都是这个大框的重复。我们打算把这个大框开发成一个独立的组件,由于星星在后面其他地方有复用,星星这个部分我们也开发成一个独立的组件。
首页组件的开发
在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>
效果如下:
页面包括了标题和滚动条,还差星星,下面我们开发星星组件,并在这个页面引入。
星星的布局
代码如下:
<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>
效果如下:
根据评分动态渲染星星
<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>
效果如下:
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.js
的globalUrls
,完成业务处理后记得导出。
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.js
的network
。
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.wxml
给moreurl
属性赋值时添加了一个一个参数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
,怎么引不用啰嗦了吧。
这样,列表页以及网络重构就全部完成了,刚开始做可能有些陌生,没关系,慢慢来。
小插曲:
点开更多发现怎么这样子的?
查资料发现是flex-wrap:wrap
控制水平折行排列的,可我也写了呀,哪肯定是什么地方影响了。
后来发现
这里也定义了一个container
样式,删掉就好了。这个教训告诉我们知识一定要全面呀,知识全面思路才清晰。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。