微信小程序實戰,用vue3實現每日浪漫情話推薦~


1、前言

之前做了個戀愛話術微信小程序,滿足了日常聊天的需要,實現高情商的戀愛聊天。最近也完成了話術庫的優化更新,新增30萬條話術數據,同時使用了分詞技術,匹配更完善。

但最近突然發現,每天早上給女朋友發一段優美情話可以讓她開心一整天,但無奈自己的語言水平確實有限,不能隨手拈來,着實讓人有點不爽。

不過辦法總比困難多,作為高情商的程序猿,來源於日常生活的需求往往是咱們最大的動力,必須盤他,所以想着在之前的戀愛話術小程序上在加一個每日情話推薦的功能。
希望這個程序對其他單身或者戀愛中的兄弟們有所幫助,也希望兄弟們關注加三連支持一波哈~~~

2、推薦接口簡介

辣雞服務器,兄弟們輕點調哈

浪漫推薦情話開放接口

接口地址:https://yin-feng.top/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": ""
	}
]

3、前端頁面開發

老樣子,咱們還是使用uniapp框架來開發,uniapp的介紹就不多說了哈。

3.1 配置pages.json文件

我們這次打算配兩個菜單,包括浪漫情話推薦和話術搜索。主要在pages.json里面就行配置。

pages.json 文件用來對 uni-app 進行全局配置,決定頁面文件的路徑、窗口樣式、原生的導航欄、底部的原生tabbar 等。它類似微信小程序中app.json的頁面管理部分。

pages.json 中提供 tabBar 配置,不僅僅是為了方便快速開發導航,更重要的是在App和小程序端提升性能。在這兩個平台,底層原生引擎在啟動時無需等待js引擎初始化,即可直接讀取 pages.json 中配置的 tabBar 信息,渲染原生tab。

官方文檔參考tabBar

特別注意

  1. 當設置 position 為 top 時,將不會顯示 icon
  2. tabBar 中的 list 是一個數組,只能配置最少2個、最多5個 tab,tab 按數組的順序排序。
  3. tabbar 切換第一次加載時可能渲染不及時,可以在每個tabbar頁面的onLoad生命周期里先彈出一個等待雪花(hello uni-app使用了此方式)
  4. tabbar 的頁面展現過一次后就保留在內存中,再次切換 tabbar 頁面,只會觸發每個頁面的onShow,不會再觸發onLoad。
  5. 頂部的 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"
	}
}

在這里插入圖片描述

3.2 封裝api接口

主要在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

3.3 編寫浪漫情話頁面

咱們還是使用vue3加uniapp的語法進行頁面開發,同時為了使頁面更優美,封裝一個瀑布流組件進行渲染數據。下圖就是咱們要實現的大致效果

在這里插入圖片描述

3.3.1 封裝瀑布流組件

<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>

3.3.2 template代碼編寫

這里在引入瀑布流組件之后可直接在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>

3.3.3 js核心方法編寫

關鍵代碼也不多,主要是一些請求數據的方法和響應式變量的定義。

<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>

3.3.4 css樣式代碼編寫

咱們畢竟不是專業的前端,所以樣式就隨便應付一下就行,兄弟們不要介意哈

<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>

在這里插入圖片描述

4、發布微信小程序

發布流程參考這篇博客戀愛話術微信小程序

在這里插入圖片描述
兄弟們可以掃描下面的太陽碼進行體驗哈

在這里插入圖片描述

5、總結

源碼地址在這哈,會保持一直開源,希望兄弟們多多支持,下了源碼的老鐵麻煩點個star哈

// 下了源碼的老鐵麻煩點個star哈
https://gitee.com/yinfeng-code/love-chat-wx.git

肝文不易,希望對其他單身或者戀愛中的兄弟們有所幫助,也希望兄弟們關注加三連支持一波哈


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM