# project
**Repository Path**: xiao_kailang/project
## Basic Information
- **Project Name**: project
- **Description**: 小程序项目
- **Primary Language**: JavaScript
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2021-07-26
- **Last Updated**: 2021-11-18
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README

# 仿王者荣耀小程序-攻略页面
## 前言
"上号上号!!!你在干什么呢"
无论在何时何地身边总是会响起这熟悉的话语,这貌似在大学生生活中很普遍。
可惜可惜,本人什么游戏都玩,什么都不精,那我就必须在学习、工作方面努力了。
 作为一名在校生,小程序是一种对全栈项目最好的练习,也是一个必备的知识点。正好王者荣耀小程序是一个不错的小程序,其中也有一个攻略页面。
开冲!

- 更新记录 2021/8/22更新新闻点赞效果
## IDE
- [微信开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html?t=201822)
- [Fiddler](https://www.telerik.com/download/fiddler) 抓包软件,可以抓取小程序里的图片
- [Mark Man](http://www.getmarkman.com/) 测量设计图片内响应的样式
## 总体架构
- 该项目是微信小程序云开发项目,使用wxml+wxss+js+component+云数据库结合,命名格式采用[BEM](https://blog.csdn.net/weixin_59695963/article/details/118586222)格式。
```js
|-wzry 项目名
|-cloudfunctions 云函数模块
|-miniprogram 项目模块
|-components 自定义组件
|-herosType 英雄信息排列组件
|-navBarTitle 自定义topbar组件
|-newsPoster 新闻文章组件
|-data 自定义数据
|-allHeros.js 封装获取云数据
|-acticleData.js 用户文章数据
|-circleList.js 新闻文章数据和新闻类型列表
|-herosMap.js 英雄图鉴中最新英雄
|-herosRank.js 3个上分英雄
|-segment.js 段位排行
|-upScoreData.js 上分页面数据
|-miniprogram_npm 构建有赞组件库
|-pages 页面
|-introduction 攻略主页面
|-upScore 上分宝典页面
|-heros 全部英雄页面
|-search 搜索页面
|-style 样式库
weui.wxss weui样式库
app.js 全局js
app.json 全局json配置
app.wxss 全局wxss
```
其中的data文件下全为固定数据,采用`module.exports`暴露,在需要使用的地方,可以使用`const {getHeroOrderByType} = require("../../data/allHeros")`进行引入,这里`{}`使用的是es6 的`解构`,当然也可以直接用一个常量接受使用。
关于云数据库,我采用的是`csv`格式进行`导入小程序云数据库表`中,`csv`格式制作,可以先创建一个`excel文件`进行编辑数据,然后`另存为csv格式`,需要注意的一点,文件中的中文需要转换为`utf-8编码`,可以在另存为csv格式前,先修改文件格式为txt,然后通过vscode进行修改编码格式,接着在改回excel格式,最后另存为csv格式。

## 项目规划
将项目的架构搭建后,分析各页面的功能,思考相互页面之间的联系,清楚如何进行动态数据绑定,如何获取数据,各页面有哪些细节需要注意等等。
## 项目解构
以下就是我的所有页面
| | |
| --- | --- |
|||
|  |  |
| |
### tabbar
由于微信自带的tabbar格式就可以满足王者荣耀小程序的tabbar就没有再去自定义tabbar,而是直接使用默认格式了。写在`app.json`中,pagePath只有一个页面,其他页面由团队其他人负责,我这就没有修改成他们的。
```js
"tabBar": {
"selectedColor": "#a68f5c",
"borderStyle": "white",
"backgroundColor": "#fff",
"list": [
{
"text": "主页",
"iconPath": "images/tabbar/home.png",
"pagePath": "pages/Introduction/Introduction",
"selectedIconPath": "images/tabbar/home_on.png"
},
{
"text": "精选",
"iconPath": "images/tabbar/jingxuan.png",
"pagePath": "pages/Introduction/Introduction",
"selectedIconPath": "images/tabbar/jingxuan_on.png"
},
{
"text": "攻略",
"iconPath": "images/tabbar/hero.png",
"pagePath": "pages/Introduction/Introduction",
"selectedIconPath": "images/tabbar/hero_on.png"
},
{
"text": "我",
"iconPath": "images/tabbar/wo.png",
"pagePath": "pages/Introduction/Introduction",
"selectedIconPath": "images/tabbar/wo_on.png"
}
]
},
```
### 精选主页
- **对页面分析**
#### topbar
最上面的是topbar,王者荣耀小程序和默认的topbar格式不一样,所有我选择自定义组件,
这里取名字有点错误,当时以为topbar也属于navBar的一种。o(╥﹏╥)o
```js
{{title}}
```
这里让王者荣耀四个字和右边胶囊平齐没有使用类似`wx.setNavigationBarTitle`这样的接口,而是直接使用`css`中`padding-top`一点一点调。从父组件中传入两个参数,`isback`控制是否显示回退按钮(<),`title`为页面标题,`_goback`函数控制回到上一个页面,使用的是 `wx.navigateBack `API。
#### 中间部分
新英雄排列我做成了一个组件,因为在全部英雄中复用了两次。但组件是为全部英雄分类而做的,新英雄排列没有进行修改。
```js
{{type}}
{{item.name}}
```
其结构很简单,使用了弹性布局,开启了自动换行`flex-wrap: wrap;`,在css布局中对于各英雄之间的空白,我使用的是`margin-right`,但给第5个`.heros:nth-child(5)`设置为0。
上分排行榜: 给整个盒子绑定了一个点击事件`跳转到上分界面`,同样使用的是弹性布局,使用了3次弹性布局,整个大盒子是一个弹性盒,左边的文字也是一个,右边图片也是,图片右边的箭头是用伪类来做的,通过`transform: rotate(45deg);`旋转45度达到效果
```js
.heros-upImg::after{
content: "";
width: 16rpx;
height: 16rpx;
position: absolute;
right: -16rpx;
border-top:1px solid grey ;
border-right:1px solid grey;
transform: rotate(45deg);
}
```
点击全部英雄可以跳转到全部英雄界面
#### 用户文章和直播推荐
文章类型有三种情况,我都使用假数据完成了效果
1. 文章没有图片
2. 文章只有一张图片
3. 文章有3张及以上的图片
其中我将有图片和无图片分为两种情况书写(建议可以看看注释)
```js
{{act.title}}
{{act.content}}
共{{act.imgUrl.length}}张
{{item.id}}/{{nowArry.length}}
```

- 文字部分,使用了文字超出省略,如果是文字是单行省略,则可以使用`white-space: nowrap;overflow: hidden;text-overflow:ellipsis;`如果是固定行数省略,则可以使用 `overflow: hidden;display: -webkit-box;-webkit-line-clamp: 2; -webkit-box-orient: vertical;`

- 图片是排列用的是flex布局,为了获取到图片中件部分,在这里还使用了定位,`left: 50%;top:50%;transform: translate(-50%,-50%);`做到绝对居中。

- 有图片的文章设置了有赞组件[遮罩层](https://vant-contrib.gitee.io/vant-weapp/#/overlay),通过点击事件修改`show`数据为`true`将图片放大,在组件基础上添加可以进行滑动图片,缺点是没发将右上角胶囊覆盖住。
- 遮罩层如何完成交互的呢~~~ 我给每张图片的父容器绑定了一个捕获事件(防止冒泡)`onClickShow`,然后使用`data-id="{{act.id},data-index="{{item.id}}`将数据中每篇文章的唯一标识`id`和每个图片的唯一标识`id`传入函数中(id为文章标识,index为图片标识),可以通过函数的默认参数`event`,打印event参数可以得到下图。传过来的id放在`event.currentTarget.dataset`中,显示图片和滑动图片并不难,但要保证所选的文章和图片要保持一致,(如最上方的数字)这是就需要用到传入的数据,通过`this.setData`方法将`index-1`作为`swiper`的`current`属性、`id-1`作为文章数组的下标。(这里减一的原因是我数据中都是从1开始的)。

```js
{{act.name}}
{{act.desc}}
```
- 直播推荐:这里本来是点击跳转到另一个小程序的,但我不知道其他小程序的appid,所有就放弃了跳转而是使用了一个视频代替,使用了`video`标签
### 上分宝典页面
值得一讲的地方就是这里也使用了[遮罩层](https://vant-contrib.gitee.io/vant-weapp/#/overlay),同样
这里还使用了[radio单选框组件](https://vant-contrib.gitee.io/vant-weapp/#/radio),对于交互功能,也通过引入`data中segment.js`段位数据,这里点击相应段位就会切换段位,通过对`radio`绑定点击事件传入`name`值修改data{}展示到页面的相关数据。
||
||
最下面使用了一个小动画,使用方法为css动画`@keyframes`,修改定位中的`right`起到移动的效果,期间慢慢的修改`字体图标`的`opacity`透明度

#### 最强上分榜
最强上分榜、输出狂魔榜、开始上分都是上分宝典页面的一部分,写在siwper中的`swiper-item`。两个页面布局是一样的,写两个是为了展示展示。他们的布局很普通,使用了大量的弹性布局,然后在讲数据引入,使用它主要是因为好用,当然使用其他布局手段也可以。
### 全部英雄

- 搜索框使用的是`weui`自带的搜索框,做了一点修改,点击搜索框会跳转到搜索页面进行搜索,减少全部英雄页面的负担。
- **该页面重点是下面的英雄分类,使用了云数据库。**
1. 建立好数据表
2. 引入数据表,进行筛选
3. 将筛选好的数据分类好分别插入wxml

- 建立数据表,我在开头已经写了方法,可以使用导入的方式,[英雄数据.csv](https://download.csdn.net/download/weixin_59695963/20933561),也可以自己一条一套记录添加
- 引入数据表,筛选分类,我将代码封装在`data文件`下的`allHeros.js`,注释很重要!!!!
```js
//引入云数据库
const db = wx.cloud.database()
const allHeros = db.collection("allHeros")
// 将db.command设置为一个字符,方便使用
const _ = db.command
// 设置每次获取数据记录的限制20条
const limit = 20
// 将获取数据封装为一个函数,然后只需要暴露函数就可
const getHeroOrderByType = async (type) => {
// where 对云数据库进行筛选
let {data} = await allHeros.where(_.or([{ // _.or()或语句,不同字段不同值,符合一个就ok
hero_type: _.eq(type)
},
{
hero_type2: _.eq(type)
}
])).orderBy("hero_id", "desc").get() // orderBy() 排序,desc表示降序,asc表示升序
// 因为知道所有类型的数据都不超过40条 所以只要重复一次
// 如果超过40条,可以修改判断语句改为 while(data.length==limit*index) 需要定义一个变量index储存筛选次数
if(data.length ==20){
let arr = await allHeros.where(_.or([{
hero_type: _.eq(type)
},
{
hero_type2: _.eq(type)
}
])).skip(limit).orderBy("hero_id", "desc").get();
data = [...data,...arr.data] // 将两次查询到的结果合并为一个数组
}
//返回数组
return data
}
const allOccupation = {
getHeroOrderByType
}
module.exports = allOccupation
```
- 在heros.js 引入封装好的筛选js,使用es7 的`async` 和`await` 来处理异步
```js
const {getHeroOrderByType} = require("../../data/allHeros")
const type=["战士","法师","坦克","刺客","射手","辅助"]
// 设置数据封装为函数
async getHeroType(){
this.setData({
zhanshi:await getHeroOrderByType(type[0]),
fashi:await getHeroOrderByType(type[1]),
tanke:await getHeroOrderByType(type[2]),
cike:await getHeroOrderByType(type[3]),
sheshou:await getHeroOrderByType(type[4]),
fuzhu:await getHeroOrderByType(type[5]),
})
},
onLoad(options) {
this.getNewHeros()
this.getHeroType()
this.getnewsPost()
},
```
赋值后的数组(zhanshi...)可以直接在wxml通过`wx:for="{{zhanshi}}"`使用
### 新闻点赞

上图也使用了云数据库,点击修改云数据库中的support(点赞数)和supported(是否点赞过)
- 上图使用`newsPoster组件`,交互功能:点击点赞数加1,颜色变红,在点减1,颜色恢复
将`更新数据代码`封装在`allHeros.js,`先在`父组件页面`引入allHeros.js`获取新闻数据`,然后传入`子组件`,通过`子组件`点击后将数据传入`父组件`,接着在父组件页面引入allHeros.js的`更新数据函数`:使用`where`筛选出需要修改的记录,然后使用`update`更新数据,在调用`更新数据函数`。
```js
//allHeros.js
// 获取数据
const getNewsPost = async ()=>{
let {data} = await newsPost.orderBy("id","asc").get()
return data
}
// 更新数据,修改点赞数
const updataNewsPost= async (id,support,supported)=>{
await newsPost.where({//根据自己设置的id筛选,也可以通过别的唯一字段筛选
id:_.eq(id)
}).update({
data: { //需要修改的数据
support:support,
supported:!supported
}
})
}
// 子组件
methods: {
onSupport(e){
let {support,id,supported}= e.currentTarget.dataset
// 将数据传入父组件
this.triggerEvent("support",{support,id,supported})
}
}
// 父组件页面js引入
const {updataNewsPost} = require("../../data/allHeros")
// 修改点赞数
async onSupport(e){
//获取数据
let {id,supported,support} = e.detail
//判断是否点赞过 support在数据库中默认值为false
if(!supported){
//点赞+1
await updataNewsPost(id,support+1,supported)
}else{
//点击-1
await updataNewsPost(id,support-1,supported)
}
//重新让页面获取所有数据,达到渲染页面效果
this.getnewsPost()
},
```
## 踩坑系列

- 自定义topbar的时候回会导致整个页面会往上移动,需要设置topbar的高度,同样也要修改页面相关的高度。
- 遮罩层确定点击的当前文章以及滑动的图片,需要区分它们的唯一标识,this.setData要对应好数据。
- 只有一张图片的文章,当时用css搞了很久,一直都不对劲,一直查找资料,才发现修改image中mode属性就ok,心态直接起飞。
- 云数据库筛选的时候,let {data} 一定要加{},因为函数返回的是一个promise对象,对象之中才是我们想要的数组。
## 个人体会
写完这些页面,个人感觉挺累的,虽然我负责的这些页面比较简单,交互功能较少,(云函数没用上o(╥﹏╥)o),第一次写小程序的精力,希望以后越来越好。

## 源码
[源码](https://gitee.com/xiao_kailang/project)
欢迎大家给项目一个star, 鼓励开源更多的项目, 谢谢。