Wechat Mini | Note-7

微信小程序开发 Note-7


小程序首页视频列表

首页是底色加封面图,并不是可播放的视频;

自定义mapper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<select id="queryAllVideos" resultMap="BaseResultMap" parameterType="String">
select v.*,u.face_image as face_image,u.nickname as nickname from videos v
left join users u on u.id = v.user_id
where
1 = 1
<if test=" videoDesc != null and videoDesc != '' ">
and v.video_desc like '%${videoDesc}%'
</if>
<if test=" userId != null and userId != '' ">
and v.user_id = #{userId}
</if>
and v.status = 1
order by v.create_time desc
</select>

视频列表分页查询接口

Pagehelper原理:

从数据库中select数据,在查询之前做一层拦截;

拦截后的select语句,将会由Ph做一个拼接,拼接成复合分页要求的select(limit)语句;

拼接出来的新select语句将替代原select,获取数据;

1
2
3
4
// 查询第几页,每页显示几条数据
PageHelper.startPage(page,pageSize);
List<User> list = userMapper.find();
PageInfo page = new PageInfo<list>;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Service
@Service
public class VideoServiceImpl implements VideoService {
@Autowired
private VideosMapper videosMapper;
@Autowired
private VideosMapperCustom videosMapperCustom;
@Override
public PagedResult getAllVideos(Integer page, Integer pageSize) {
PageHelper.startPage(page,pageSize);
List<VideosVO> list = videosMapperCustom.queryAllVideos();

PageInfo<VideosVO> pageList = new PageInfo<>(list);

PagedResult pagedResult = new PagedResult();
pagedResult.setPage(page);
pagedResult.setTotal(pageList.getPages());
pagedResult.setRows(list);
pagedResult.setRecords(pageList.getTotal());
return pagedResult;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Controller
@RestController
@Api(value = "VIDEO API", tags = {"VIDEO CONTROLLER"})
@RequestMapping("/video")
public class VideoController extends BasicController {

@PostMapping(value = "/showAll")
public IMoocJSONResult showAll(Integer page) {
if(page == null){
page = 1;
}
PagedResult pagedResult = videoService.getAllVideos(page,PAGE_SIZE);
return IMoocJSONResult.ok(pagedResult);
}
}

首页分页联调

wx.getSystemInfoSync() - 获取系统信息同步接口

同步返回参数说明:

参数 说明
screenWidth 屏幕宽度
screenHeight 屏幕高度
windowWidth 可使用窗口宽度
windowHeight 可使用窗口高度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
const app = getApp()
Page({
data: {
// 总页数
totalPage: 1,
// 当前页数
page: 1,
// 视频列表
videoList: [],
screenWidth: 350,
serverUrl: ""
},
onLoad: function(params) {
var me = this;
var screenWidth = wx.getSystemInfoSync().screenWidth;
me.setData({
screenWidth: screenWidth
});

// 获取当前的分页数
var page = me.data.page;
var serverUrl = app.serverUrl;
wx.showLoading({
title: '视频加载中...',
});

wx.request({
url: serverUrl + '/video/showAll?page=' + page,
method:'POST',
success:function(res){
wx.hideLoading();
console.log(res.data);
// 获取数据
// 判断当前页page是否为第一页,第一页则清空videoList
if(page === 1){
me.setData({
videoList: []
});
}

var videoList = res.data.data.rows;
var newVideoList = me.data.videoList;

me.setData({
videoList: newVideoList.concat(videoList),
page:page,
totalPage: res.data.data.total,
serverUrl:serverUrl
});
}
})
}
})

首页——上拉分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
const app = getApp()
// 并且修改共用方法
Page({
data: {
// 总页数
totalPage: 1,
// 当前页数
page: 1,
// 视频列表
videoList: [],
screenWidth: 350,
serverUrl: ""
},
// 共用方法
getAllVideoList: function(page) {
var me = this;
var serverUrl = app.serverUrl;
wx.showLoading({
title: '视频加载中...',
});
wx.request({
url: serverUrl + '/video/showAll?page=' + page,
method: 'POST',
success: function(res) {
wx.hideLoading();
console.log(res.data);
// 获取数据
// 判断当前页page是否为第一页,第一页则清空videoList
if (page === 1) {
me.setData({
videoList: []
});
}

var videoList = res.data.data.rows;
var newVideoList = me.data.videoList;

me.setData({
videoList: newVideoList.concat(videoList),
page: page,
totalPage: res.data.data.total,
serverUrl: serverUrl
});
}
});
}
// 上拉刷新
onReachBottom: function() {
var me = this;
var currentPage = me.data.page;
var totalPage = me.data.totalPage;
// 如果是最后一页,无须查询
if (currentPage === totalPage) {
wx.showToast({
title: '没有更多视频,请积极投稿',
icon: 'none'
});
return;
}
// 继续翻页
var page = currentPage + 1;
me.getAllVideoList(page);

},
// 具体的视频信息
showVideoInfo: function(e) {

}
})

首页——下拉刷新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const app = getApp()
Page({
// 共用方法
getAllVideoList: function(page) {
...
wx.request({
url: serverUrl + '/video/showAll?page=' + page,
method: 'POST',
success: function(res) {
// 隐藏刷新
wx.hideLoading();
wx.hideNavigationBarLoading();
wx.stopPullDownRefresh();
...
});
}
// 下拉刷新(需要在index.json启动事件)
onPullDownRefresh:function(){
wx.showNavigationBarLoading();
this.getAllVideoList(1);
}
})

视频组件与API

video 视频

属性名 类型 默认值 说明
src String 要播放视频的资源地址,支持云文件ID(2.2.3)
initial-time Number 指定视频初始播放位置
duration Number 指定视频时长
controls Boolean true 是否显示默认播放控件(播放/暂停按钮、播放进度、时间)
danmu-list Object Array 弹幕列表
danmu-btn Boolean false 是否显示弹幕按钮,只在初始化时有效,不能动态变更
enable-danmu Boolean false 是否展示弹幕,只在初始化时有效,不能动态变更
autoplay Boolean false 是否自动播放
loop Boolean false 是否循环播放
muted Boolean false 是否静音播放
page-gesture Boolean false 在非全屏模式下,是否开启亮度与音量调节手势
direction Number 设置全屏时视频的方向,不指定则根据宽高比自动判断。有效值为 0(正常竖向), 90(屏幕逆时针90度), -90(屏幕顺时针90度)
show-progress Boolean true 若不设置,宽度大于240时才会显示
show-fullscreen-btn Boolean true 是否显示全屏按钮
show-play-btn Boolean true 是否显示视频底部控制栏的播放按钮
show-center-play-btn Boolean true 是否显示视频中间的播放按钮
enable-progress-gesture Boolean true 是否开启控制进度的手势
wx.createVideoContext(videoId, this)

创建并返回 video 上下文 videoContext 对象。在自定义组件下,第二个参数传入组件实例this,以操作组件内 <video/>组件

videoContext

videoContext 通过 videoId 跟一个 video 组件绑定,通过它可以操作一个 video 组件


开源搜索视频组件

wsSearchView

该搜索框组件基于开源项目wxSearch 进行了改进,主要有以下几个修改点:

  • 增加了注释,修改了一些bug,项目可以跑起来。
  • 为了解决搜索框和输入法界面重叠的问题,将搜索组件作为一个独立的页面。
  • 修改了界面样式,更加美观。
  • 减少了暴露接口,复杂性更低。

搜索插件缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
function search(inputValue) {
if (inputValue && inputValue.length > 0) {
// 添加历史记录
wxSearchAddHisKey(inputValue);
// 更新
var temData = __that.data.wxSearchData;
temData.value = inputValue;
__that.setData({
wxSearchData: temData
});
// 回调搜索
__searchFunction(inputValue);
}
}

// 添加本地缓存
function wxSearchAddHisKey(inputValue) {
if (!inputValue || inputValue.length == 0) {
return;
}
var value = wx.getStorageSync('wxSearchHisKeys');
if (value) {
if (value.indexOf(inputValue) < 0) {
value.unshift(inputValue);
}
wx.setStorage({
key: "wxSearchHisKeys",
data: value,
success: function() {
getHisKeys(__that);
}
})
} else {
value = [];
value.push(inputValue);
wx.setStorage({
key: "wxSearchHisKeys",
data: value,
success: function() {
getHisKeys(__that);
}
})
}
}

修改全局用户对象(使用缓存)

为了使用户每次打开小程序不需要重复的登录,根据官方文档的同步&异步方法的说明;

需要通过设置全局的用户对象,使用本地缓存的方式,解决这样的问题;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//app.js
App({
serverUrl: "ip",
userInfo: null,
setGlobalUserInfo:function(user){
wx.setStorageSync("userInfo", user);
},
getGlobalUserInfo: function () {
return wx.getStorageSync("userInfo");
}
})

// app.userInfo = res.data.data;
// fixme 修改原有全局对象为本地缓存
app.setGlobalUserInfo(res.data.data);
// fixme 修改原有全局对象为本地缓存
var userInfo = app.getGlobalUserInfo();
// 注销后,清空缓存
wx.removeStorageSync("userInfo");

查询接口完善 & 热搜词保存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Service
package com.imooc.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.imooc.mapper.SearchRecordsMapper;
import com.imooc.mapper.VideosMapper;
import com.imooc.mapper.VideosMapperCustom;
import com.imooc.pojo.SearchRecords;
import com.imooc.pojo.Videos;
import com.imooc.pojo.vo.VideosVO;
import com.imooc.service.VideoService;
import com.imooc.utils.PagedResult;
import org.n3r.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class VideoServiceImpl implements VideoService {
@Autowired
private VideosMapper videosMapper;
@Autowired
private VideosMapperCustom videosMapperCustom;
@Autowired
private SearchRecordsMapper searchRecordsMapper;
@Autowired
private Sid sid;

@Transactional(propagation = Propagation.REQUIRED)
@Override
public PagedResult getAllVideos(Videos video, Integer isSaveRecord, Integer page, Integer pageSize) {
// 保存热搜词记录
String desc = video.getVideoDesc();
if(isSaveRecord != null && isSaveRecord == 1){
SearchRecords record = new SearchRecords();
record.setId(sid.nextShort());
record.setContent(desc);
searchRecordsMapper.insert(record);
}
// 视频分页查询
PageHelper.startPage(page, pageSize);
List<VideosVO> list = videosMapperCustom.queryAllVideos(desc);

PageInfo<VideosVO> pageList = new PageInfo<>(list);

PagedResult pagedResult = new PagedResult();
pagedResult.setPage(page);
pagedResult.setTotal(pageList.getPages());
pagedResult.setRows(list);
pagedResult.setRecords(pageList.getTotal());
return pagedResult;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
// VideosMapperCustom.xml
<select id="queryAllVideos" resultMap="BaseResultMap" parameterType="String">
select v.*,u.face_image as face_image,u.nickname as nickname from videos v
left join users u on u.id = v.user_id
where
1 = 1
<if test=" videoDesc != null and videoDesc != '' ">
and v.video_desc like '%${videoDesc}%'
</if>
and v.status = 1
order by v.create_time desc
</select>

热搜词查询接口

1
2
3
4
5
6
7
// SearchRecordsMapper.xml
<select id="getHotwords" resultType="String">
SELECT content
FROM search_records
GROUP BY content
ORDER BY count(content) DESC
</select>
1
2
3
4
5
6
7
8
9
10
11
12
// Service
@Service
public class VideoServiceImpl implements VideoService {
@Autowired
private SearchRecordsMapper searchRecordsMapper;

@Transactional(propagation = Propagation.SUPPORTS)
@Override
public List<String> getHotwords() {
return searchRecordsMapper.getHotwords();;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// Controller
@RestController
@Api(value = "VIDEO API", tags = {"VIDEO CONTROLLER"})
@RequestMapping("/video")
public class VideoController extends BasicController {
@Autowired
private VideoService videoService;

@PostMapping(value = "/hot")
public IMoocJSONResult hot() {
return IMoocJSONResult.ok(videoService.getHotwords());
}
}

热搜词联调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...  
// 2 搜索栏初始化(热搜词)
onLoad: function() {
var that = this;
// 查询热搜词
var serverUrl = app.serverUrl;
wx.request({
url: serverUrl+'/video/hot',
method:'POST',
success:function(res){
console.log(res);
var hotList = res.data.data;
// 搜索栏初始化
WxSearch.init(
that, // 本页面一个引用
// ['慕课网', "小程序", 'SpringBoot', 'linux'], 热点搜索推荐,[]表示不使用
hotList,
hotList, // 搜索匹配,[]表示不使用
that.mySearchFunction, // 提供一个搜索回调函数
that.myGobackFunction //提供一个返回回调函数
);
}
});
}...
})