发布时间:2023-08-24
统计字数:1696 字
阅读时间:9 min read
之前在抖音刷到过一个视频,就是视频主使用一款 App,这个 App 可以随机获取国内的城市,并且可以进行筛选。然后博主就通过这个 App,去拍旅游视频。
然后我想着好像还蛮有意思,想做一个出来玩一下。那么安卓应用我虽然说还不太了解开发,然后微信小程序我还是懂一点的嘛。然后我就打算以微信小程序为平台做一个出来耍耍。
要做微信小程序的话,可以选择使用官方的开发方式来做,也可以使用 Uniapp 来做,那么为了后续有可能会使用到数据库等处理,我选择使用 Uniapp 来写,毕竟它提供了一个免费云函数和云数据库。而且只要你学会 Vue3,那么无论是微信小程序还是 Uniapp 其实都一样。
Uniapp 的优点有以下:
所以我选择了使用 Uniapp 来进行开发。
我这里是直接使用官方的 Cli 来进行开发,这里既可以直接使用官方的 Hbuilder 来创建项目,也可以使用命令行来,使用 Cli 的话,项目的目录结构更符合我们平时 Node 开发的项目结构。
创建项目的命令这里我就直接贴官方的链接了。创建命令
接着就是安装 Unocss,这里是安装配置。 安装配置
通过视频可以得知操作逻辑是点击转盘中间的按钮,转盘则会开始转动,同时上方的城市名称会不停变化,最终停留在随机获取的城市上。
首先是如何开发这个转盘,最重要的是这个城市数据,这个数据必须要有省,二级城市的相关数据,然后在 Github 搜索一番就可以获得。省份数据
获取到的省份数据还不能够使用,必须先把省和二级城市单独区分出来,这个使用 Python 可以很简单地做到。最终数据呈现这样子。
上面是城市数据,而省份数据则是这样。
既然有了数据,那么就可以开发转盘了。一开始想的是这个转盘其实就是城市的名字,围着一个圆而已,但是网上大多都是围着一个边来。
这样子并不能满足需求,然后我就接着搜,最后找到了一个相似的 demo。文字绕圆demo链接
但是这样子还不行,可以看到视频上文字自身也是带角度的,每个文字都是指向外边,而不是横着来,那么问题就来到了如何让文本竖着来。结果刚好有一个 css 属性可以做到这样子。
writing-mode:vertical-lr;
顺便放上 MDN 的链接 MDN属性说明
ok,这样子就可以做出来了。
其实如果不是小程序的话,还有一种方式更简单实现,那就是使用 SVG 的 textpath,但是很可惜,在小程序中 svg标签并不能使用。
那好,盘是做出来了,但是怎么转呢?这个问题刚好官方就有一个 api 可以解决。
const animation = wx.createAnimation({
duration: 6000,
timingFunction: 'ease',
delay: 0
})
具体的属性这里放上链接。微信官方文档
duration 设置为6000,也就是6秒,然后动画的效果是 ease,也就是官方所说的 动画以低速开始,然后加快,在结束前变慢
。
然后这里我让它旋转360度。
animationData.value = animation.rotate(360).step().export()
这里是实现的效果
然后接下来就是上方的城市展示,这里我做了一个工具类来获取所有的城市。
import areaJson from "@/constant/city.json";
import province from "@/constant/province.json";
/**
* 随机获取旅游城市
* @param {Array} exclude - 要排除的城市 ID 数组
* @returns 返回城市信息
*/
export const randomGetArea = (exclude = []) => {
// 读取 constant 中的 json
const area = areaJson;
// 随机获取城市
const city = area[Math.floor(Math.random() * area.length)];
// 如果城市在排除列表中,则重新获取
if (exclude.includes(city.cityId)) {
return randomGetArea(exclude);
}
return city;
};
export const randomGetAreaExclude = (
excludeCityId = [],
excludeProvinceId = [],
) => {
const area = areaJson;
const citys = area.filter(
(item) =>
!excludeProvinceId.includes(String(item.pid)) &&
!excludeCityId.includes(item.id),
);
// 随机获取城市
const city = citys[Math.floor(Math.random() * citys.length)];
return city;
};
读取城市数据的 JSON 文件,然后随机获取。在动画执行的时候通过不断随机获取来达到视频的那种效果。下面是这个随机展示城市的方法。
const animationHandle = () => {
if (city.value !== '点击转盘开始') {
return;
}
// 旋转360度
animationData.value = animation.rotate(360).step().export()
// 获取城市集合
const list = listCityExclude([], excludeProvinceId.value || []);
let index = 0;
// 定时器获取
animationHandleInterval.value = setInterval(() => {
if (index >= 60) {
clearInterval(animationHandleInterval.value);
return;
}
city.value = list[Math.floor(Math.random() * list.length)].name;
index++;
}, 100);
animationHandleTimeOut.value = setTimeout(() => {
clearInterval(animationHandleInterval.value);
}, 6000);
};
这样子就实现了转盘上随机展示城市的功能了,那么不管是随机展示,还是转盘动画转动,都需要一个最终确认的城市,同时这个城市还得在动画结束后最终展示。其实这个可以利用 刚才微信的动画 api 来解决。
官方有一个事件,那么只要通过这个事件回调,就能做到确定最终城市了。
那么核心功能都已完成,现在就剩下样式和一些布局了。这部分就没啥好说了。在后续迭代中我还加上了省份筛选功能,这部分就运用到了 Pinia
这个状态处理库,还有这个状态持久化的库 pinia-plugin-unistorage
。
import { defineStore } from "pinia";
export const useAreaStore = defineStore(
"area",
() => {
const excludeCityId = ref([]);
const excludeProvinceId = ref([]);
const setExcludeCityId = (id) => {
excludeCityId.value.push(id);
};
const setExcludeProvinceId = (id) => {
excludeProvinceId.value.push(id);
};
const removeExcludeCityId = (id) => {
excludeCityId.value = excludeCityId.value.filter((item) => item !== id);
};
const removeExcludeProvinceId = (id) => {
excludeProvinceId.value = excludeProvinceId.value.filter(
(item) => item !== id,
);
};
return {
excludeCityId,
excludeProvinceId,
setExcludeCityId,
setExcludeProvinceId,
removeExcludeCityId,
removeExcludeProvinceId,
};
},
{
unistorage: true,
},
);
通过记录用户的筛选,并持久化,来达到目标功能。
这里的界面做得潦草一点,不过还有搜索功能,也算是麻雀虽小,五脏俱全了。
后续还有很大的迭代空间,例如用户功能,用户转盘结果记录,通过AI来进行旅游地推荐等等。最终成为一个合格的小程序。
同时我也通过这次开发得到了许多关于 css 的知识,以及关于 Uniapp 的开发经验。后续迭代的功能,我将会记录在博客上。