之前做了个[恋爱话术微信小程序],满足了日常聊天的需要,实现高情商的恋爱聊天。最近也完成了话术库的优化更新,新增30万条话术数据,同时使用了分词技术,匹配更完善。
但最近突然发现,每天早上给女朋友发一段优美情话可以让她开心一整天,但无奈自己的语言水平确实有限,不能随手拈来,着实让人有点不爽。
不过办法总比困难多,作为高情商的程序猿,来源于日常生活的需求往往是咱们最大的动力,必须盘他,所以想着在之前的恋爱话术小程序上在加一个每日情话推荐的功能。
希望这个程序对其他单身或者恋爱中的兄弟们有所帮助,也希望兄弟们关注加三连支持一波哈~~~
辣鸡服务器,兄弟们轻点调哈
接口地址:https://yin-feng.top/open/getRecommendLove/open/getRecommendLove
请求方式:POST
请求数据类型:application/json
响应数据类型:*/*
请求参数:
{}
响应参数:
参数名称 | 参数说明 | 类型 | schema |
---|---|---|---|
content | 内容 | string | |
id | id | integer(int64) | integer(int64) |
score | 分数 | integer(int32) | integer(int32) |
title | 标题 | string |
响应示例:
[ { "content": "", "id": 0, "score": 0, "title": "" } ]
老样子,咱们还是使用uniapp框架来开发,uniapp的介绍就不多说了哈。
我们这次打算配两个菜单,包括浪漫情话推荐和话术搜索。主要在pages.json里面就行配置。
pages.json 文件用来对 uni-app 进行全局配置,决定页面文件的路径、窗口样式、原生的导航栏、底部的原生tabbar 等。它类似微信小程序中app.json的页面管理部分。
在 pages.json 中提供 tabBar 配置,不仅仅是为了方便快速开发导航,更重要的是在App和小程序端提升性能。在这两个平台,底层原生引擎在启动时无需等待js引擎初始化,即可直接读取 pages.json 中配置的 tabBar 信息,渲染原生tab。
官方文档参考tabBar
特别注意
- 当设置 position 为 top 时,将不会显示 icon
- tabBar 中的 list 是一个数组,只能配置最少2个、最多5个 tab,tab 按数组的顺序排序。
- tabbar 切换第一次加载时可能渲染不及时,可以在每个tabbar页面的onLoad生命周期里先弹出一个等待雪花(hello uni-app使用了此方式)
- tabbar 的页面展现过一次后就保留在内存中,再次切换 tabbar 页面,只会触发每个页面的onShow,不会再触发onLoad。
- 顶部的 tabbar 目前仅微信小程序上支持。需要用到顶部选项卡的话,建议不使用 tabbar 的顶部设置,而是自己做顶部选项卡。
新增浪漫情话页面配置
{ "path": "pages/recommend/recommend", "style": { "navigationBarTitleText": "浪漫情话", "backgroundColor": "#eeeeee", "enablePullDownRefresh": false } }
添加两个tab标签
"tabBar": { "color": "#7A7E83", "selectedColor": "#0055ff", "borderStyle": "black", "backgroundColor": "#ffffe1", "height":"60px", "fontSize":"18px", "list": [ { "pagePath": "pages/recommend/recommend", "iconPath": "static/imgs/love1.png", "selectedIconPath": "static/imgs/love2.png", "text": "浪漫情话" }, { "pagePath": "pages/index/index", "iconPath": "static/imgs/爱心1.png", "selectedIconPath": "static/imgs/爱心2.png", "text": "话术搜索" } ] }
完整的page.json文件
{ "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages { "path": "pages/recommend/recommend", "style": { "navigationBarTitleText": "浪漫情话", "backgroundColor": "#eeeeee", "enablePullDownRefresh": false } }, { "path": "pages/index/index", "style": { "navigationBarTitleText": "恋爱话术", "backgroundColor": "#eeeeee", "enablePullDownRefresh": false } }, { "path": "component/WebView/WebView", "style": { "navigationBarTitleText": "", "enablePullDownRefresh": false } } ], "tabBar": { "color": "#7A7E83", "selectedColor": "#0055ff", "borderStyle": "black", "backgroundColor": "#ffffe1", "height":"60px", "fontSize":"18px", "list": [ { "pagePath": "pages/recommend/recommend", "iconPath": "static/imgs/love1.png", "selectedIconPath": "static/imgs/love2.png", "text": "浪漫情话" }, { "pagePath": "pages/index/index", "iconPath": "static/imgs/爱心1.png", "selectedIconPath": "static/imgs/爱心2.png", "text": "话术搜索" } ] }, "globalStyle": { "navigationBarTextStyle": "black", "navigationBarTitleText": "恋爱话术", "navigationBarBackgroundColor": "#ffffe1", "backgroundColor": "#f5ffff" } }
主要在http.api.js里面配置,这个文件之前也包含了咱们的话术搜索接口
import service from './http.interceptor.js' const api = { // 话术搜索 getLoveChat: params => service.post('/open/getLoveChat', params), getBanner: () => service.post('/open/getBanner'), // 浪漫情话推荐 getRecommendLove: () => service.post('/open/getRecommendLove'), loveScore: params => service.post('/open/loveScore', params), } export default api
咱们还是使用vue3加uniapp的语法进行页面开发,同时为了使页面更优美,封装一个瀑布流组件进行渲染数据。下图就是咱们要实现的大致效果
<template> <view class="u-waterfall"> <view id="u-left-column" class="u-column"> <slot name="left" :leftList="leftList"></slot> </view> <view id="u-right-column" class="u-column"> <slot name="right" :rightList="rightList"></slot> </view> </view> </template> <script> export default { name: "waterfall", props: { value: { // 瀑布流数据 type: Array, required: true, default: function() { return []; } } }, data() { return { leftList: [], rightList: [], tempList: [] } }, watch: { copyFlowList(nVal, oVal) { this.tempList = this.cloneData(this.copyFlowList); this.leftList = [] this.rightList = [] this.splitData(); } }, mounted() { this.tempList = this.cloneData(this.copyFlowList); this.splitData(); }, computed: { // 破坏flowList变量的引用,否则watch的结果新旧值是一样的 copyFlowList() { return this.cloneData(this.value); } }, methods: { async splitData() { if (!this.tempList.length) return; let leftRect = await this.$uGetRect('#u-left-column'); let rightRect = await this.$uGetRect('#u-right-column'); // 如果左边小于或等于右边,就添加到左边,否则添加到右边 let item = this.tempList[0]; // 解决多次快速上拉后,可能数据会乱的问题,因为经过上面的两个await节点查询阻塞一定时间,加上后面的定时器干扰 // 数组可能变成[],导致此item值可能为undefined if (!item) return; if (leftRect.height < rightRect.height) { this.leftList.push(item); } else if (leftRect.height > rightRect.height) { this.rightList.push(item); } else { // 这里是为了保证第一和第二张添加时,左右都能有内容 // 因为添加第一张,实际队列的高度可能还是0,这时需要根据队列元素长度判断下一个该放哪边 if (this.leftList.length <= this.rightList.length) { this.leftList.push(item); } else { this.rightList.push(item); } } // 移除临时列表的第一项 this.tempList.splice(0, 1); // 如果临时数组还有数据,继续循环 if (this.tempList.length) { this.splitData(); } else { // 在这里模拟触发 我们定义的全局事件 实现数据通信的目的 let height = (leftRect.height > rightRect.height ? leftRect.height : rightRect.height) + 120 uni.$emit('swiperHeightChange', height + 'px') } }, // 复制而不是引用对象和数组 cloneData(data) { return JSON.parse(JSON.stringify(data)); }, } } </script> <style lang="scss" scoped> @mixin vue-flex($direction: row) { /* #ifndef APP-NVUE */ display: flex; flex-direction: $direction; /* #endif */ } .u-waterfall { @include vue-flex; flex-direction: row; align-items: flex-start; } .u-column { @include vue-flex; flex: 1; flex-direction: column; height: auto; } .u-image { width: 100%; } </style>
这里在引入瀑布流组件之后可直接在html里面使用
<template> <view> <view class="change" @click="changeContent"> 没找到想要的?赶紧点击这里 <text class="change-btn">换一批</text> <view class="card"> 点击下方卡片可直接复制 </view> </view> <waterfall :value="dataList"> <template v-slot:left="left"> <view v-for="item in left.leftList" :key="item.id" class="left-content" @click="copy(item)"> <view class="item"> {{item.content}} </view> </view> </template> <template v-slot:right="right"> <view v-for="item in right.rightList" :key="item.id" class="right-content" @click="copy(item)"> <view class="item"> {{item.content}} </view> </view> </template> </waterfall> </view> </template>
关键代码也不多,主要是一些请求数据的方法和响应式变量的定义。
<script> import { toRefs, reactive, onMounted } from 'vue' import waterfall from '../../component/waterfall/index.vue' import api from '../../axios/http.api.js' export default { name: 'content', components: { waterfall }, setup() { const state = reactive({ dataList: [], loading: false, }) const methods = reactive({ getRecommendLove: async () => { state.loading = true let res = await api.getRecommendLove() state.loading = false if (res.code) { uni.showToast({ title: res.msg, icon: 'none', position: 'top' }) } state.dataList = res.data }, copy(item) { // 复制话术到剪切板 uni.setClipboardData({ data: item.content }) methods.score(item.id) }, // 换一批 changeContent() { methods.getRecommendLove() }, // 打分 async score(id) { let res = await api.loveScore({ id }) if (res.code) { uni.showToast({ title: res.msg, icon: 'none', position: 'top' }) } } }) onMounted(() => { methods.getRecommendLove() // 分享菜单 wx.showShareMenu({ withShareTicket: true, menus: ['shareAppMessage', 'shareTimeline'] }) }) return { ...toRefs(state), ...toRefs(methods) } } } </script>
咱们毕竟不是专业的前端,所以样式就随便应付一下就行,兄弟们不要介意哈
<style lang="less" scoped> .change { width: 100%; height: 120px; border-bottom: 2px #aaaaff solid; border-radius: 0 0 50px 50px; background-size: 100% 100%; opacity: 0.8; padding-top: 45px; text-align: center; font-size: 20px; color: #000000; background-image: url(../../static/imgs/img4.png); .change-btn { display: inline-block; padding: 2px; color: red; } .card { padding-top: 12px; font-size: 13px; } } .left-content { margin: 15px 5px 15px 10px; padding: 8px; border-radius: 6px; background: #aaffff linear-gradient(44deg, #aaffff 0%, #F4F8FF 100%); font-size: 16px; letter-spacing: 5px; .item { margin-bottom: 10px; } } .right-content { margin: 15px 10px 15px 5px; padding: 8px; border-radius: 6px; background: #aaffff linear-gradient(44deg, #aaffff 0%, #F4F8FF 100%); font-size: 16px; letter-spacing: 5px; .item { margin-bottom: 10px; } } </style>
发布流程参考这篇博客[恋爱话术微信小程序]
兄弟们可以扫描下面的太阳码进行体验哈
源码地址在这哈,会保持一直开源,希望兄弟们多多支持,下了源码的老铁麻烦点个star哈
// 下了源码的老铁麻烦点个star哈 https://gitee.com/yinfeng-code/love-chat-wx.git
肝文不易,希望对其他单身或者恋爱中的兄弟们有所帮助,也希望兄弟们关注加三连支持一波哈