当前位置: 首页 > news >正文

uniapp 微信小程序仿抖音评论区功能,支持展开收起

最近需要写一个评论区功能,所以打算仿照抖音做一个评论功能,支持展开和收起,

首先我们需要对功能做一个拆解,评论区功能,两个模块,一个是发表评论模块,一个是评论展示区。接下来对这两个模块进行详细描述。

使用到的技术 uniapp  uview2.0   文章最后我会贴上全部源码

一、发表评论模块

这个模块使用uview的两个组件来完成分别是u-popup弹出层和u-input输入框

下面是代码和展示图:

<u-popup :show="talkShow" mode="bottom" :customStyle="{'width':'100%','border-radius':'8rpx'}" @close="popclosed" @open="keyboard=true" :safeAreaInsetBottom="true"><view class="flex justify-between align-center" style="padding: 32rpx;"><div class="cirbOX padding-left padding-right-sm"><u--form labelPosition="left" :model="talkData" :rules="Rules" ref="Form" :borderBottom="false"><u-form-item label=" " prop="txt" :borderBottom="false" ref="item1" labelWidth='0'><u--input :focus="keyboard" v-model="talkData.txt" cursorSpacing="30" maxlength="100" :placeholder="pinglunHolder" border="none" clearable></u--input></u-form-item></u--form></div><div class="submitpinglun" @click="submit">发布</div></view></u-popup>

这部分需要注意两点

1.input组件的focus属性的设置:

在弹出层弹出的时候 在open事件中对input的focus属性布尔值设置为true,close时候设置focus为false。这样做的目的是在弹出输入评论的弹窗时会拉起小键盘,这个交互方式是模仿的微信朋友圈发布评论的形式。

2.input的cursorSpacing属性(输入框聚焦时底部与键盘的距离)设置:

当键盘拉起时候整个输入框因为设置了cursorSpacing="30",故整体页面会被小键盘托起。 当收起小键盘时候,输入框有回归到手机底部,因为我们popup设置的是底部的弹出层。这样是和微信朋友圈发布评论是对标的。

二、展示评论区的功能

这一部分我封装成了组件,因为需求的要求需要下拉加载评论故在组件外部循环一级评论,组件内部展示一级评论和二级评论,其中二级评论是在组件内部去循环,

循环一级评论的时候需要注意,因为后续要获取pinglun组件的实例,所以在ref的设置上面起初我按照for循环提供的index来拼的字符串,这也导致后续bug的出现埋下伏笔,所以我后续调整了,选择了id这个唯一值作为组件实例的ref名字,这个很关键!

<div v-for="(item,index) in onePagePinglunList" :key="item.id" class="margin-bottom"><pinglun :ref="`pinglun-${item.levelOneCommentVo.id}`" :caseIdData="caseId" :data="item" :indexxx="index" @comment="goComment" @noLogin="sonNoLogin"></pinglun></div>

组件代码:

<template><div><!-- 一级评论 --><div class="flex justify-start align-start margin-bottom-sm"><div class="margin-right-xs"><d-image :dSrc="onePageList.levelOneCommentVo.userAvatar" dMode="aspectFit" dWidth="72rpx" dHeight="72rpx"></d-image></div><div class="flex-sub"><div class="flex justify-start align-center"><div class="name margin-right-sm">{{onePageList.levelOneCommentVo.userName}}</div><div class="zuozhe flex justify-center align-center" v-if="onePageList.levelOneCommentVo.belongAuthor===1">作者</div></div><div class="flex justify-between align-center" @click="goPinglun(1,onePageList.levelOneCommentVo.id,onePageList.levelOneCommentVo.userName,onePageList.levelOneCommentVo.id)"><div class="content flex-sub">{{onePageList.levelOneCommentVo.content}}</div><div class="flex flex-direction align-center" style="width: 68rpx;" @click.stop="likepinglun(1,'',onePageList.levelOneCommentVo.id)"><div class="margin-bottom-xs"><div v-show="onePageList.levelOneCommentVo.isCurrentUserLike===0"><u-icon name="heart" color="#667286" size="34rpx"></u-icon></div><div v-show="onePageList.levelOneCommentVo.isCurrentUserLike===1"><u-icon name="heart-fill" color="red" size="34rpx"></u-icon></div></div><div class="likeNum">{{onePageList.levelOneCommentVo.likeCount}}</div></div></div><div class="time">{{ $u.timeFrom(new Date(onePageList.levelOneCommentVo.createTime).getTime())}}</div></div></div><!-- 二级评论 --><div class="erpinglunBox" :style="{'height':`${pingjiaBoxMaxHeight}px`,'opacity':pinglunOpcity,}"><div class="pinglunDom"><div v-for="(item,index) in onePageList.twoLevelpinglun" :key="item.id" class="margin-bottom-sm"><div class="flex justify-start align-start"><div class="margin-right-xs"><d-image :dSrc="item.userAvatar" dMode="aspectFit" dWidth="72rpx" dHeight="72rpx"></d-image></div><div class="flex-sub"><div class="flex justify-start align-center"><div class="name margin-right-sm">{{item.userName}}</div><div class="zuozhe flex justify-center align-center margin-right-sm" v-if="item.belongAuthor===1">作者</div><div class="name" v-if="item.isReplayTwoComment===1">回复 {{item.replayLevelTwoCommentUser.userName}}</div></div><div class="flex justify-between align-center" @click="goPinglun(2,item.id,item.userName,onePageList.levelOneCommentVo.id)"><div class="content flex-sub">{{item.content}}</div><div class="flex flex-direction align-center" style="width: 68rpx;" @click.stop="likepinglun(2,index,item.id)"><div class="margin-bottom-xs"><div v-show="item.isCurrentUserLike===0"><u-icon name="heart" color="#667286" size="34rpx"></u-icon></div><div v-show="item.isCurrentUserLike===1"><u-icon name="heart-fill" color="red" size="34rpx"></u-icon></div></div><div class="likeNum">{{item.likeCount}}</div></div></div><div class="time">{{ $u.timeFrom(new Date(item.createTime).getTime())}}</div></div></div></div></div></div><!-- 展开和收起按钮 --><div class="flex justify-start align-center" style="padding-left: 84rpx;"><div class="seeMore padding-top-sm padding-bottom flex align-center" v-if="onePageList.levelTwoCommentCount > 0&&params.current <= totalPage" @click="$u.throttle(getTwoLevelPinglun, 1000,true)"><div class="margin-right-xs">查看更多回复</div><u-icon name="arrow-down" color="#00875A" size="28rpx" :bold="true"></u-icon></div><div class="seeMore retract padding-top-sm padding-bottom margin-left flex justify-center align-center" v-if="params.current > 1" @click="$u.throttle(retract, 1000,true)"><div class="margin-right-xs">收起</div><u-icon name="arrow-up" color="#00875A" size="28rpx" :bold="true"></u-icon></div></div></div>
</template>

感觉唯一的难点在于因为展开收缩使用的过渡动画,大家应该都知道,想使用这个过渡必须设置有效值,也就是说比如我给高度写过渡动画,从一个高度到一个高度,都需要是具体的值,atuo这种被内容撑开的高度是不作数的。

这里拿高度,需要注意的是需要等待渲染完毕再去获取高度,不然拿到的值就是不准确的。

下面是我写的获取高度的函数。如果一个nexttick也获取不到准确高度,那么就再加个延时器,就差不多可以获取到准确高度了。

	updatHeight() {let that = thisthis.$nextTick(() => {// this.timer = setTimeout(() => {this.createSelectorQuery().select(".pinglunDom").boundingClientRect(function(rect) {// console.log(rect);that.pingjiaBoxMaxHeight = rect.heightthat.pinglunOpcity = 1}).exec();// }, 0)})},

还有一个需要注意的点,就是在一级评论发布之后,需要拿到所有pinglu组件的实例去调用这个方法,重置所有二级评论的高度。调用这个方法的前提也必须是一级评论的渲染完毕,不然还是不起作用

以下是代码:

this.$forceUpdate();this.$nextTick(() => {for (let i = 0; i < this.onePagePinglunList.length; i++) {this.$refs[`pinglun-${this.onePagePinglunList[i].levelOneCommentVo.id}`][0].updatHeight() if (this.onePagePinglunList[i].twoLevelpinglun.length === 0) {this.$refs[`pinglun-${this.onePagePinglunList[i].levelOneCommentVo.id}`][0].params.current = 1}}}) 

至此应该就没什么需要注意的地方了

可能也是第一次写这个功能,还有很多可以优化的地方。希望对各位有所帮助,接下来我把评论功能所有源码贴在下面。

因为我的评论功能是在案例详情里面的,所以有两个文件,一个是案例详情,一个就是封装的评论组件 

案例详情:

<template><div :style="{'padding-bottom':`${(safeAreaBottom*2)+144}`+'rpx'}"><div style="padding: 32rpx 32rpx 50rpx;"><div class="margin-bottom-sm txt-1">成功蜕变历程</div><div class="toplicheng flex justify-center align-center margin-bottom-sm"><div class="flex flex-direction align-center"><div class="flex align-center"><d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/caseDetailIcON2.png" dMode="aspectFit" dWidth="32rpx" dHeight="32rpx"></d-image><div class="toptxt1 margin-left-xs">体重</div></div><div class="toptxt2 margin-top-xs">{{topweightcha||0}}kg</div></div><div class="midBox flex flex-direction align-center"><div class="xmonth flex justify-center align-center margin-bottom-xs">逆糖3个月</div><div class="topshuxian"></div></div><div class="flex flex-direction align-center"><div class="flex align-center"><d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/caseDetailIcON1.png" dMode="aspectFit" dWidth="32rpx" dHeight="32rpx"></d-image><div class="toptxt1 margin-left-xs">空腹血糖</div></div><div class="toptxt2 margin-top-xs">{{topxuetangcha||0}}mmol/L</div></div></div><!-- 案例信息 --><div class="caseBox"><div class="case-head-box flex justify-between align-center"><div class="head-left-box flex"><div class="avatarBox"><u-avatar :src="detailData.userInfoVo.userAvatar || 'https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/healthy.png'" size="72rpx" mode="aspectFill"></u-avatar></div><div><div class="txt-1 margin-bottom-xs">{{detailData.userInfoVo.userName||'暂无昵称'}}</div><div class="txt-2">{{detailData.isExistServicePack?detailData.servicePackVo.servicePackName:'暂无服务包'}}</div></div></div><div class=" flex justify-center align-center" style="width: 80rpx;height: 80rpx;"><u-icon name="share-square" color="" size="34rpx"></u-icon></div></div><div class="caseBoxContentBox"><u-row justify="space-start"><u-col span="4"><view class="txt-4 margin-bottom">项目</view></u-col><u-col span="4"><view class="txt-4 margin-bottom">管理前</view></u-col><u-col span="4"><view class="txt-4 margin-bottom">管理后</view></u-col></u-row><u-row justify="space-start"><u-col span="4"><view><div class="txt-3">服务时间</div></view></u-col><u-col span="4"><view><div class="startTime">{{detailData.managementInfoVo.managementStartTime||'--'}}</div></view></u-col><u-col span="4"><view><div class="endTime">{{detailData.managementInfoVo.managementEndTime||'--'}}</div></view></u-col></u-row><div class="line"></div><u-row justify="space-start"><u-col span="4"><view><div class="txt-3">体重</div><div class="txt-7">kg</div></view></u-col><u-col span="4"><view><div class="yellow-box flex justify-center align-center" style="position: relative;">{{detailData.managementInfoVo.beforeManagementWeight||'--'}}<div class="jiantou" v-if="detailData.managementInfoVo.beforeManagementFastingSugarBloodTrend===3"><d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/redUp.png" dMode="aspectFit" dWidth="24rpx" dHeight="24rpx"></d-image></div><div class="jiantou" v-else-if="detailData.managementInfoVo.beforeManagementFastingSugarBloodTrend===1"><d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/greenDown.png" dMode="aspectFit" dWidth="24rpx" dHeight="24rpx"></d-image></div></div></view></u-col><u-col span="4"><view><div class="green-box flex justify-center align-center">{{detailData.managementInfoVo.afterManagementWeight||'--'}}</div></view></u-col></u-row><div class="line"></div><u-row justify="space-start"><u-col span="4"><view><div class="txt-3">空腹血糖</div><div class="txt-7">mmol/L</div></view></u-col><u-col span="4"><view><div class="yellow-box flex justify-center align-center" style="position: relative;">{{detailData.managementInfoVo.beforeManagementFastingSugarBlood||'--'}}<div class="jiantou"v-if="detailData.managementInfoVo.beforeManagementWeightTrend===3||detailData.managementInfoVo.beforeManagementWeightTrend===4||detailData.managementInfoVo.beforeManagementWeightTrend===5"><d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/redUp.png" dMode="aspectFit" dWidth="24rpx" dHeight="24rpx"></d-image></div><div class="jiantou" v-else-if="detailData.managementInfoVo.beforeManagementWeightTrend===1"><d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/greenDown.png" dMode="aspectFit" dWidth="24rpx" dHeight="24rpx"></d-image></div></div></view></u-col><u-col span="4"><view><div class="green-box flex justify-center align-center">{{detailData.managementInfoVo.afterManagementFastingSugarBlood||'--'}}</div></view></u-col></u-row><div class="line"></div><u-row justify="space-start"><u-col span="4"><view><div class="txt-3">用药数量</div></view></u-col><u-col span="4"><view><div class="yellow-box flex justify-center align-center">{{detailData.managementInfoVo.beforeManagementMedicationCount||'0'}}</div></view></u-col><u-col span="4"><view><div class="green-box flex justify-center align-center">{{detailData.managementInfoVo.afterManagementMedicationCount||'0'}}</div></view></u-col></u-row><div class="line"></div><u-row justify="space-start"><u-col span="4"><view><div class="txt-3">对比照片</div></view></u-col><u-col span="4"><view><div class="margin-bottom-sm"><div><div v-if="detailData.managementInfoVo.beforeManagementImagePhoto===''" class="noPicBox flex justify-center align-center">暂无</div><div v-else><d-image :dSrc="detailData.managementInfoVo.beforeManagementImagePhoto" dMode="aspectFit" dWidth="140rpx" dHeight="140rpx"></d-image></div></div></div></view></u-col><u-col span="4"><view><div class="margin-bottom-sm"><div><div v-if="detailData.managementInfoVo.afterManagementImagePhoto===''" class="noPicBox flex justify-center align-center">暂无</div><div v-else><d-image :dSrc="detailData.managementInfoVo.afterManagementImagePhoto" dMode="aspectFit" dWidth="140rpx" dHeight="140rpx"></d-image></div></div></div></view></u-col></u-row></div></div><!-- 评价 --><div class="evaluateBox margin-top-sm margin-bottom-sm"><div class="margin-bottom-sm txt-1">健康评价</div><div class="margin-top-sm flex flex-wrap pingjiaBox"><view class="pingjiaDom"><div v-for="(item,index) in defaultPingjia" :key="item.id" class="flex "><div class="tag margin-right-sm flex align-center margin-bottom-sm" :style="{'background':item.styleBg}"><div style="height: 100%; " class="flex align-start margin-right-sm"><d-image :dSrc="item.styleIcon" dMode="aspectFit" dWidth="26rpx" dHeight="26rpx"></d-image></div><text :style="{'max-width': '544rpx','word-break': 'break-all','color':item.styleColor}">{{item.content}}</text></div></div></view></div></div><!-- echart --><!-- 	<div class="margin-bottom-sm" style="position: relative;overflow: hidden;" v-for="(item,index) in echartList" :key="index"><detailChart :echarType="item"></detailChart></div> --></div><!-- 评论 --><div style="padding: 0 32rpx 56rpx;background: #FFFFFF;"><div class="flex justify-between align-center"><div class="pingluntitle">{{detailData.interActionVo.commentCount||'0'}} 评论</div><div></div></div><div v-for="(item,index) in onePagePinglunList" :key="item.id" class="margin-bottom"><pinglun :ref="`pinglun-${item.levelOneCommentVo.id}`" :caseIdData="caseId" :data="item" :indexxx="index" @comment="goComment" @noLogin="sonNoLogin" @shouqi="shouqiTwoPinglun"></pinglun></div></div><div class="contentB">- 让每个人都能从知识中获得健康 -</div><!-- 底部评价评论点赞收藏 --><div class="pingjialikeBox flex justify-between align-center" :style="{'bottom':`${(safeAreaBottom*2)}`+'rpx'}"><div class="talksomething flex justify-center align-center" @click="openPinglun">说点什么吧</div><div class="flex justify-around" style="width: 428rpx;"><div class="flex align-center btn" @click="$u.throttle(clickLike, 500,true)"><div v-show="detailData.interActionVo.isCurrentUserLike===0"><u-icon name="heart" color="" size="34rpx"></u-icon></div><div v-show="detailData.interActionVo.isCurrentUserLike===1"><u-icon name="heart-fill" color="red" size="34rpx"></u-icon></div><text class="margin-left-xs">{{detailData.interActionVo.likeCount||'0'}}</text></div><div class="flex align-center btn" @click="$u.throttle(clickCollect, 500,true)"><div v-show="detailData.interActionVo.isCurrentUserCollection===0"><u-icon name="star" color="" size="34rpx"></u-icon></div><div v-show="detailData.interActionVo.isCurrentUserCollection===1"><u-icon name="star-fill" color="#ff991f" size="34rpx"></u-icon></div><text class="margin-left-xs">{{detailData.interActionVo.collectionCount||'0'}}</text></div><div class=" flex align-center btn"><u-icon name="chat" color="" size="34rpx"></u-icon><text class="margin-left-xs">{{detailData.interActionVo.commentCount||'0'}}</text></div></div></div><u-popup :show="talkShow" mode="bottom" :customStyle="{'width':'100%','border-radius':'8rpx'}" @close="popclosed" @open="keyboard=true" :safeAreaInsetBottom="true"><view class="flex justify-between align-center" style="padding: 32rpx;"><div class="cirbOX padding-left padding-right-sm"><u--form labelPosition="left" :model="talkData" :rules="Rules" ref="Form" :borderBottom="false"><u-form-item label=" " prop="txt" :borderBottom="false" ref="item1" labelWidth='0'><u--input :focus="keyboard" v-model="talkData.txt" cursorSpacing="30" maxlength="100" :placeholder="pinglunHolder" border="none" clearable></u--input></u-form-item></u--form></div><div class="submitpinglun" @click="submit">发布</div></view></u-popup><u-modal title="确认登录" :show="show1" width="608rpx" content="为了您的良好体验,建议您先确认登录 ~" :closeOnClickOverlay="true" @close="show1=false"><u-button slot="confirmButton" text="确定" shape="circle" color="#00875A" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber" :customStyle="{'width':'264rpx','height':'68rpx'}"></u-button></u-modal><u-toast ref="uToast"></u-toast></div>
</template><script>import { mapState } from 'vuex';import detailChart from "./detailEchart.vue"import pinglun from "./pinglun.vue"import { sub } from '@/utils/tool.js'import { getDetail, getCurveModule, collection, like, savecomment, getLevelOnePage } from '@/api/case/case.js'export default {data() {return {show1: false,keyboard: false,pinglunHolder: '说点什么吧',Rules: {'txt': [{required: true,type: 'any',message: '评论不能为空',trigger: ['blur', 'change']},{validator: (rule, value, callback) => {return value.length < 100;},message: '您评论的字数超过100,请调整您的字数~',trigger: ['blur', 'change']}],},talkShow: false,talkData: { //弹框form值 评论txt: ""},caseId: null,echartList: [],detailData: {},defaultPingjia: [],topweightcha: null,topxuetangcha: null,pinglunForm: { //接口参数caseId: null,caseLevelOneCommentId: '', //对一级评论进行回复时不可为空caseLevelTwoCommentId: '', //对二级评论进行回复时不可为空content: null,userId: null,},params: {current: 1,limit: 5,likeSort: 2, //点赞数排序 1:升序 2:降序timeSort: 2, //创建时间排序 1:升序 2:降序},totalPage: 1,onePagePinglunList: [],pinglunType: null, //判断用户评论的类型是案例评论(3)还是一级评论(1)还是二级评论(2)erpinglunIndex: 0, //暂存二级评论发送给父级组件给的一级评论的index}},components: { detailChart, pinglun },computed: {...mapState(["hasLogin", "safeAreaBottom", "userInfo", ])},// 发送给朋友onShareAppMessage(res) {return {title: '妙智健康案例',path: `/pages-caseStory/caseDetail/index?caseId=${this.caseId}&title=${this.detailData.userInfoVo.userName}`}},//分享到朋友圈onShareTimeline(res) {return {title: '妙智健康案例',query: `caseId=${this.caseId}&title=${this.detailData.userInfoVo.userName}`,path: `/pages-caseStory/caseDetail/index` //自定义路径拼参数会导致接收参数会失败}},onReady() {},onLoad(option) {this.$refs.Form.setRules(this.Rules)this.caseId = option?.caseIduni.setNavigationBarTitle({title: `${option.title||''}案例`});this.getdetailData()this.getLevelOnePageData()},onUnload() {// this.$store.commit('set_caseShareEchartPicList', [])},onShow() {},methods: {sub,async getPhoneNumber(e) {// console.log("获取手机号code", e) //获取手机号已经不需要先进行wx.login(最新文档)if (!e.detail.code) {uni.showToast({title: '登录需要获取您的手机号',icon: 'none',duration: 2500})return}let resss = await this.$store.dispatch("loginFn", e) //能同步拿到vux中mutaion的resolve,然后给fourDataNum赋值(登录后数据更新)console.log(resss);if (resss.state === 1) { //登录成功this.show1 = false}},async getdetailData() {uni.showLoading({title: '加载中...'})try {let res = await getDetail({caseId: this.caseId,userId: this.hasLogin ? this.userInfo?.userId : ''})let echarRes = await getCurveModule({caseId: this.caseId,})if (res.state === 1) {this.detailData = res.contentthis.defaultPingjia = res.content.personnelEvaluationVoListthis.topweightcha = this.sub(this.detailData.managementInfoVo.afterManagementWeight, this.detailData.managementInfoVo.beforeManagementWeight)this.topxuetangcha = this.sub(this.detailData.managementInfoVo.afterManagementFastingSugarBlood, this.detailData.managementInfoVo.beforeManagementFastingSugarBlood)}if (echarRes.state === 1) {this.echartList = echarRes.content.map(item => {let obj = {title: item.caseCurveType === 1 ? '硅基' : (item.caseCurveType === 2 ? "微策" : "体重"),defaultTime: item.caseCurveType === 1 ? item.curveStartDate : [item.curveStartDate, item.curveEndDate],userId: res.content.userInfoVo.userId}return obj})}uni.hideLoading();} catch (e) {uni.hideLoading();uni.$u.toast(e)}},async clickLike(item, index) {if (!this.hasLogin) {this.show1 = truereturn}try {let res = await like({userId: this.userInfo?.userId,caseId: this.caseId,})if (res.state === 1) {if (this.detailData.interActionVo.isCurrentUserLike === 1) {this.detailData.interActionVo.isCurrentUserLike = 0this.detailData.interActionVo.likeCount--} else if (this.detailData.interActionVo.isCurrentUserLike === 0) {this.detailData.interActionVo.isCurrentUserLike = 1this.detailData.interActionVo.likeCount++}}} catch (e) {uni.$u.toast(e)}},async clickCollect(item) {if (!this.hasLogin) {this.show1 = truereturn}try {let res = await collection({userId: this.userInfo?.userId,caseId: this.caseId,})if (res.state === 1) {if (this.detailData.interActionVo.isCurrentUserCollection === 1) {this.detailData.interActionVo.isCurrentUserCollection = 0this.detailData.interActionVo.collectionCount--} else if (this.detailData.interActionVo.isCurrentUserCollection === 0) {this.detailData.interActionVo.isCurrentUserCollection = 1this.detailData.interActionVo.collectionCount++}}} catch (e) {uni.$u.toast(e)}},popclosed() {this.talkData.txt = ''this.keyboard = falsethis.talkShow = falseconsole.log(this.keyboard);},async getLevelOnePageData() {uni.showLoading({title: '加载中...'})try {let res = await getLevelOnePage({ userId: this.hasLogin ? this.userInfo?.userId : '', caseId: Number(this.caseId), ...this.params })if (res.state === 1) {for (let i = 0; i < res.content.records.length; i++) {res.content.records[i].twoLevelpinglun = []if (this.onePagePinglunList.some(item => item.levelOneCommentVo.id === res.content.records[i].levelOneCommentVo.id)) { //删除重复项res.content.records.splice(i, 1)}}this.onePagePinglunList = [...this.onePagePinglunList, ...res.content.records]this.totalPage = Math.ceil(res.content.total / this.params.limit) //总页数=总数量/每页数量}uni.hideLoading();} catch (e) {uni.hideLoading();uni.$u.toast(e)}},openPinglun() {if (!this.hasLogin) {this.show1 = truereturn}this.pinglunType = 3 //案例评论this.pinglunHolder = '说点什么吧'this.pinglunForm.caseLevelOneCommentId = '' //不回复一二级评论时候置空该字段this.pinglunForm.caseLevelTwoCommentId = '' //不回复一二级评论时候置空该字段this.talkShow = true// this.keyboard = true},goComment(e) { //处理回复一级二级评论  案例的顶级评论在openPinglun()函数中console.log(e);this.pinglunType = e.type //评论类型console.log('this.pinglunType', this.pinglunType);if (e.type === 1) { //一级评论this.pinglunForm.caseLevelOneCommentId = e.idthis.erpinglunIndex = e.indexthis.pinglunHolder = `回复 @${e.replyName}`} else if (e.type === 2) { //二级评论this.pinglunForm.caseLevelTwoCommentId = e.idthis.erpinglunIndex = e.indexthis.pinglunHolder = `回复 @${e.replyName}`}console.log("点击的item", this.$refs[`pinglun-${this.erpinglunIndex}`][0].onePageList);this.talkShow = true// this.keyboard = trueconsole.log(this.keyboard);},async submit() {this.pinglunForm.userId = this.userInfo.userIdthis.pinglunForm.content = this.talkData.txtthis.pinglunForm.caseId = this.caseId// let form = {// 	caseId: this.caseId,// 	caseLevelOneCommentId: '', //对一级评论进行回复时不可为空// 	caseLevelTwoCommentId: '', //对二级评论进行回复时不可为空// 	content: this.talkData.txt,// 	userId: this.userInfo.userId,// }try {let res = await savecomment(this.pinglunForm)if (res.state === 1) {if (this.pinglunType === 3) { //案例评论this.onePagePinglunList.unshift({twoLevelpinglun: [],...res.content.caseCommentHomeVo})this.$forceUpdate();this.$nextTick(() => {for (let i = 0; i < this.onePagePinglunList.length; i++) {this.$refs[`pinglun-${this.onePagePinglunList[i].levelOneCommentVo.id}`][0].updatHeight() //重置子组件内部height 不管新增一级还是二级都需要全部重置高度不然会出现bugif (this.onePagePinglunList[i].twoLevelpinglun.length === 0) {this.$refs[`pinglun-${this.onePagePinglunList[i].levelOneCommentVo.id}`][0].params.current = 1}}console.log(this.$refs[`pinglun-${127}`][0].onePageList);})this.$forceUpdate();} else if (this.pinglunType === 1 || this.pinglunType === 2) { //回复一级评论或二级评论  push完需要注意的是在获取分页数据时候去重,因为这个push操作是模拟更新数据,后端并不知晓所以后端未做去重console.log(this.$refs[`pinglun-${this.erpinglunIndex}`][0].onePageList.twoLevelpinglun);this.$refs[`pinglun-${this.erpinglunIndex}`][0].onePageList.twoLevelpinglun.push({...res.content.caseLevelTwoCommentVo})console.log(this.$refs[`pinglun-${this.erpinglunIndex}`][0].onePageList.twoLevelpinglun);let indxx;for (let i = 0; i < this.onePagePinglunList.length; i++) {if (this.onePagePinglunList[i].levelOneCommentVo.id === this.erpinglunIndex) {indxx = ibreak}}// 目的是防止发表一级评论之后父级向下重新注入数据,会触发pinglun组件内部的watch,导致会重置组件内部的twoLevelpinglun为[],this.onePagePinglunList[indxx].twoLevelpinglun = this.$refs[`pinglun-${this.erpinglunIndex}`][0].onePageList.twoLevelpinglunthis.onePagePinglunList[indxx].levelTwoCommentCount++this.$refs[`pinglun-${this.erpinglunIndex}`][0].updatHeight() //重置子组件内部height}this.talkData.txt = '' //重置评论this.keyboard = false //自动聚焦设为falsethis.talkShow = false //关闭弹窗this.updatePinglunNum() //更新评论数量console.log(this.keyboard);this.$refs.uToast.show({type: 'success',message: "已发送评论~",duration: 1200,})}} catch (e) {uni.$u.toast(e)}},sonNoLogin(e) {console.log(e);if (!this.hasLogin) {this.show1 = truereturn}},async updatePinglunNum() {try {let res = await getDetail({caseId: this.caseId,userId: this.hasLogin ? this.userInfo?.userId : ''})if (res.state === 1) {this.detailData = res.content}} catch (e) {uni.$u.toast(e)}},//因为每次发表二级评论都会往父级的twoLevelpinglun添加属性,也就是submit函数里面的565行代码,会导致一个bug 就是发布二级评论后,// 因为同时给父级也赋值了,故收起二级评论后,再发表一级评论,重置了了渲染,会将父级被赋值的twoLevelpinglun同步到二级评论的twoLevelpinglun,相当于之前收起操作白重置了twoLevelpinglunshouqiTwoPinglun(index) {let indxx;for (let i = 0; i < this.onePagePinglunList.length; i++) {if (this.onePagePinglunList[i].levelOneCommentVo.id === index) {indxx = ibreak}}this.onePagePinglunList[indxx].twoLevelpinglun = []},},// 上拉加载async onReachBottom() {if (this.params.current > this.totalPage) {this.$refs.uToast.show({type: 'warning',message: "已经到底啦~",duration: 1200,})return}this.params.current += 1await this.getLevelOnePageData()uni.stopPullDownRefresh() //停止上拉加载},// 下拉刷新触发async onPullDownRefresh() {this.params.current = 1 //重置页码this.onePagePinglunList = []await this.getLevelOnePageData()this.$refs.uToast.show({type: 'success',message: "刷新成功",duration: 1200,})uni.stopPullDownRefresh() //停止下拉刷新},}
</script><style lang="scss" scoped>@import '@/pages-caseStory/style/caseCommon.scss';.pingluntitle {font-size: 28rpx;font-family: PingFangSC;color: #1F3253;height: 90rpx;line-height: 90rpx;}.contentB {margin: 42rpx 0;font-size: 24rpx;font-weight: 400;color: #667286;text-align: center;}.pingjialikeBox {padding: 32rpx;width: 100%;height: 144rpx;background: #FFFFFF;position: fixed;left: 0;.btn {height: 70rpx;width: 78rpx;}}.toplicheng {height: 160rpx;background: linear-gradient(47deg, rgba(23, 144, 109, 0.84) 0%, #5DC063 100%);border-radius: 12rpx;}.topshuxian {width: 1rpx;height: 80rpx;opacity: 0.5;border: 2rpx solid #FFFFFF;}.xmonth {width: 156rpx;height: 47rpx;background: #FFFFFF;border-radius: 0rpx 0rpx 14rpx 14rpx;opacity: 0.8;font-size: 24rpx;font-weight: 400;color: #00875A;}.toptxt1 {font-size: 28rpx;font-weight: 400;color: #FFFFFF;}.toptxt2 {font-size: 36rpx;font-weight: bold;color: #E2FFF5;}.midBox {width: 156rpx;height: 160rpx;margin-left: 70rpx;margin-right: 23rpx;}.noPicBox {width: 140rpx;height: 140rpx;background: #E7EFF6;}.jiantou {position: absolute;top: 0;right: 0;}.evaluateBox {background: #FFFFFF;border-radius: 12rpx;padding: 40rpx 32rpx 78rpx;.tag {background: #FFF6E9;border-radius: 30rpx;padding: 20rpx 30rpx 20rpx 20rpx;vertical-align: center;}}.talksomething {width: 248rpx;height: 80rpx;background: #F4F5F7;border-radius: 40rpx;font-size: 28rpx;font-weight: 400;color: #697588;}.cirbOX {width: 600rpx;height: 80rpx;background: #F4F5F7;border-radius: 40rpx;}.submitpinglun {height: 80rpx;width: 64rpx;font-size: 32rpx;font-weight: 500;color: #00875A;line-height: 80rpx;}
</style>

pinglun组件:

<template><div><!-- 一级评论 --><div class="flex justify-start align-start margin-bottom-sm"><div class="margin-right-xs"><d-image :dSrc="onePageList.levelOneCommentVo.userAvatar" dMode="aspectFit" dWidth="72rpx" dHeight="72rpx"></d-image></div><div class="flex-sub"><div class="flex justify-start align-center"><div class="name margin-right-sm">{{onePageList.levelOneCommentVo.userName}}</div><div class="zuozhe flex justify-center align-center" v-if="onePageList.levelOneCommentVo.belongAuthor===1">作者</div></div><div class="flex justify-between align-center" @click="goPinglun(1,onePageList.levelOneCommentVo.id,onePageList.levelOneCommentVo.userName,onePageList.levelOneCommentVo.id)"><div class="content flex-sub">{{onePageList.levelOneCommentVo.content}}</div><div class="flex flex-direction align-center" style="width: 68rpx;" @click.stop="likepinglun(1,'',onePageList.levelOneCommentVo.id)"><div class="margin-bottom-xs"><div v-show="onePageList.levelOneCommentVo.isCurrentUserLike===0"><u-icon name="heart" color="#667286" size="34rpx"></u-icon></div><div v-show="onePageList.levelOneCommentVo.isCurrentUserLike===1"><u-icon name="heart-fill" color="red" size="34rpx"></u-icon></div></div><div class="likeNum">{{onePageList.levelOneCommentVo.likeCount}}</div></div></div><div class="time">{{ $u.timeFrom(new Date(onePageList.levelOneCommentVo.createTime).getTime())}}</div></div></div><!-- 二级评论 --><div class="erpinglunBox" :style="{'height':`${pingjiaBoxMaxHeight}px`,'opacity':pinglunOpcity,}"><div class="pinglunDom"><div v-for="(item,index) in onePageList.twoLevelpinglun" :key="item.id" class="margin-bottom-sm"><div class="flex justify-start align-start"><div class="margin-right-xs"><d-image :dSrc="item.userAvatar" dMode="aspectFit" dWidth="72rpx" dHeight="72rpx"></d-image></div><div class="flex-sub"><div class="flex justify-start align-center"><div class="name margin-right-sm">{{item.userName}}</div><div class="zuozhe flex justify-center align-center margin-right-sm" v-if="item.belongAuthor===1">作者</div><div class="name" v-if="item.isReplayTwoComment===1">回复 {{item.replayLevelTwoCommentUser.userName}}</div></div><div class="flex justify-between align-center" @click="goPinglun(2,item.id,item.userName,onePageList.levelOneCommentVo.id)"><div class="content flex-sub">{{item.content}}</div><div class="flex flex-direction align-center" style="width: 68rpx;" @click.stop="likepinglun(2,index,item.id)"><div class="margin-bottom-xs"><div v-show="item.isCurrentUserLike===0"><u-icon name="heart" color="#667286" size="34rpx"></u-icon></div><div v-show="item.isCurrentUserLike===1"><u-icon name="heart-fill" color="red" size="34rpx"></u-icon></div></div><div class="likeNum">{{item.likeCount}}</div></div></div><div class="time">{{ $u.timeFrom(new Date(item.createTime).getTime())}}</div></div></div></div></div></div><!-- 展开和收起按钮 --><div class="flex justify-start align-center" style="padding-left: 84rpx;"><div class="seeMore padding-top-sm padding-bottom flex align-center" v-if="onePageList.levelTwoCommentCount > 0&&params.current <= totalPage" @click="$u.throttle(getTwoLevelPinglun, 1000,true)"><div class="margin-right-xs">查看更多回复</div><u-icon name="arrow-down" color="#00875A" size="28rpx" :bold="true"></u-icon></div><div class="seeMore retract padding-top-sm padding-bottom margin-left flex justify-center align-center" v-if="params.current > 1" @click="$u.throttle(retract, 1000,true)"><div class="margin-right-xs">收起</div><u-icon name="arrow-up" color="#00875A" size="28rpx" :bold="true"></u-icon></div></div></div>
</template><script>import { mapState } from 'vuex';import { commentlike, getLevelOnePage, getLevelTwoPage } from '@/api/case/case.js'export default {data() {return {caseId: null,indexxxx: null, //一级评论的indexparams: {current: 1,limit: 5,timeSort: 1, //创建时间排序 1:升序 2:降序},totalPage: 1,onePageList: {},pingjiaBoxMaxHeight: 0,pinglunOpcity: 0,timer: null,timer1: null,}},props: {caseIdData: {type: Number,// 定义是否必须传required: true,// 定义默认值default: 0},data: {type: Object,// 定义是否必须传required: true,// 定义默认值default: {}},indexxx: {type: Number,// 定义是否必须传required: true,// 定义默认值default: 0}},watch: {caseIdData: {immediate: true,handler(val) {this.caseId = val;}},data: {immediate: true,handler(val) {this.onePageList = val;}},indexxx: {immediate: true,handler(val) {this.indexxxx = val;}}},components: {},computed: {...mapState(["hasLogin", "userInfo"])},mounted() {},beforeDestroy() {clearTimeout(this.timer)clearTimeout(this.timer1)},methods: {async likepinglun(type, index, id) {if (!this.hasLogin) {this.$emit('noLogin', '一二级评论点赞未登录')return}let form = {};if (type === 1) {form.caseLevelOneCommentId = id} else if (type === 2) {form.caseLevelTwoCommentId = id}try {let res = await commentlike({ ...form, userId: this.userInfo?.userId })if (res.state === 1) { //如果接口回调成功if (type === 1) { //如果点击的是一级评论的点赞if (this.onePageList.levelOneCommentVo.isCurrentUserLike === 0) { //判断点赞之前是0还是1 然后取反  并且对应点赞数量同步加减this.onePageList.levelOneCommentVo.isCurrentUserLike = 1this.onePageList.levelOneCommentVo.likeCount++} else if (this.onePageList.levelOneCommentVo.isCurrentUserLike === 1) {this.onePageList.levelOneCommentVo.isCurrentUserLike = 0this.onePageList.levelOneCommentVo.likeCount--}} else if (type === 2) { //如果点击的是二级评论的点赞if (this.onePageList.twoLevelpinglun[index].isCurrentUserLike === 0) {this.onePageList.twoLevelpinglun[index].isCurrentUserLike = 1this.onePageList.twoLevelpinglun[index].likeCount++} else if (this.onePageList.twoLevelpinglun[index].isCurrentUserLike === 1) {this.onePageList.twoLevelpinglun[index].isCurrentUserLike = 0this.onePageList.twoLevelpinglun[index].likeCount--}}}} catch (e) {uni.$u.toast(e)}},goPinglun(e, id, name, indexx) {if (e === 1) { //一级评论this.$emit('comment', {type: e,id: id,// index: this.indexxxx,index: indexx,replyName: name, //点击的谁的评论进行回复,用于在输入框的placeholder回显})} else if (e === 2) { //二级评论this.$emit('comment', {type: e,id: id,// index: this.indexxxx,index: indexx,replyName: name, //点击的谁的评论进行回复,用于在输入框的placeholder回显})}},async getTwoLevelPinglun() {try {let res = await getLevelTwoPage({ userId: this.hasLogin ? this.userInfo?.userId : '', caseLevelOneCommentId: this.onePageList.levelOneCommentVo.id, ...this.params })if (res.state === 1) {for (let i = 0; i < res.content.records.length; i++) {res.content.records[i].twoLevelpinglun = []if (this.onePageList.twoLevelpinglun.some(item => item.id === res.content.records[i].id)) { //删除重复项res.content.records.splice(i, 1)console.log("发现重复项,删除他!!!");}}this.onePageList.twoLevelpinglun = [...this.onePageList.twoLevelpinglun, ...res.content.records]this.totalPage = Math.ceil(res.content.total / this.params.limit) //总页数=总数量/每页数量this.params.current += 1this.updatHeight()}} catch (e) {uni.$u.toast(e)}},retract() {this.pingjiaBoxMaxHeight = 0this.pinglunOpcity = 0this.params.current = 1this.onePageList.twoLevelpinglun = []this.timer1 = setTimeout(() => { //因为展开动画需要1s 故 在收起的时候延迟置空数组,console.log(this.onePageList);this.$emit('shouqi', this.onePageList.levelOneCommentVo.id)}, 800)},updatHeight() {let that = thisthis.$nextTick(() => {// this.timer = setTimeout(() => {this.createSelectorQuery().select(".pinglunDom").boundingClientRect(function(rect) {// console.log(rect);that.pingjiaBoxMaxHeight = rect.heightthat.pinglunOpcity = 1}).exec();// }, 0)})},}}
</script><style lang="scss" scoped>.name {font-size: 24rpx;font-weight: 400;color: #667286;}.content {font-size: 28rpx;font-weight: 400;color: #1F3253;}.time {font-size: 20rpx;font-weight: 400;color: #AFAFAF;}.likeNum {font-size: 20rpx;font-weight: 400;color: #667286;}.zuozhe {width: 60rpx;height: 28rpx;background: #FFFFFF;border-radius: 18rpx;border: 1rpx solid #00875A;font-size: 20rpx;font-weight: 400;color: #00875A;}.seeMore {font-size: 24rpx;font-weight: 400;color: #00875A;}.retract {width: 150rpx;text-align: center;}.erpinglunBox {padding-left: 84rpx;transition: height 1s, opacity 2s;overflow: hidden;}
</style>

案例详情引入的scss文件:

	.font-20 {font-size: 20rpx;font-weight: 400;}.font-24 {font-size: 24rpx;font-weight: 400;}.txt-1 {font-size: 28rpx;font-weight: 500;color: #0F2C50;}.txt-2 {@extend .font-20;color: #667286;}.txt-3 {@extend .font-24;color: #667286;}.txt-4 {font-size: 24rpx;font-weight: 500;color: #667286;}.txt-5 {font-size: 36rpx;font-weight: bold;}.txt-6 {@extend .font-24;color: #9CADC6;}.txt-7 {@extend .font-20;color: #B7BCC3;}.txt-8 {@extend .font-24;color: #fff;}.txt-9 {@extend .font-24;color: #0F2C50;}.txt-10 {font-size: 28rpx;font-weight: 400;color: #667286;}.yell-green-base {width: 140rpx;height: 52rpx;border-radius: 2rpx;font-size: 36rpx;font-weight: bold;}.yellow-box {@extend .yell-green-base;background-color: #FFF4CD;color: #FF991F;}.green-box {@extend .yell-green-base;background: #E2FFEE;color: #00875A;}.timeFont{font-size: 32rpx;font-family: DINAlternate-Bold, DINAlternate;font-weight: bold;}.startTime{@extend .timeFont;color: #FF991F;}.endTime{@extend .timeFont;color: #00875A;}.line {height: 1rpx;border: 1rpx solid #E6E6E6;margin: 16rpx 0;}
.caseBox {background: #FFFFFF;border-radius: 12rpx;margin-top: 20rpx;padding: 0 32rpx;.case-head-box {height: 140rpx;}.avatarBox {width: 72rpx;height: 72rpx;margin-right: 16rpx;}.caseDetailBtn {width: 100rpx;height: 44rpx;background: #00875A;border-radius: 22rpx;}.rateBox {height: 80rpx;}.mar-80 {margin-right: 80rpx;}}

相关文章:

uniapp 微信小程序仿抖音评论区功能,支持展开收起

最近需要写一个评论区功能&#xff0c;所以打算仿照抖音做一个评论功能&#xff0c;支持展开和收起&#xff0c; 首先我们需要对功能做一个拆解&#xff0c;评论区功能&#xff0c;两个模块&#xff0c;一个是发表评论模块&#xff0c;一个是评论展示区。接下来对这两个模块进行…...

js:创建一个基于vite 的React项目

相关文档 Vite 官方中文文档React 中文文档React RouterRedux 中文文档Ant Design 5.0Awesome React 创建vite react项目 pnpm create vite react-app --template react# 根据提示&#xff0c;执行命令 cd react-app pnpm install pnpm run dev项目结构 $ tree -L 1 . ├─…...

论文阅读_医疗知识图谱_GraphCare

英文名称: GraphCare: Enhancing Healthcare Predictions with Open-World Personalized Knowledge Graphs 中文名称: GraphCare&#xff1a;通过开放世界的个性化知识图增强医疗保健预测 文章: http://arxiv.org/abs/2305.12788 代码: https://github.com/pat-jj/GraphCare 作…...

Android 蓝牙开发( 四 )

前言 上一篇文章给大家分享了Kotlin版的Android蓝牙的基础知识和基础用法&#xff0c;不过上一篇都是一些零散碎片化的程序&#xff0c;&#xff0c;这一篇给大家分享Android蓝牙开发实战项目KotlinCompose的初步使用 效果演示 : Android Compose 蓝牙开发 Android蓝牙实战开发…...

涂鸦智能携手亚马逊云科技 共建“联合安全实验室” 为IoT发展护航

2023年8月31日&#xff0c;全球化IoT开发者平台涂鸦智能&#xff08;NYSE: TUYA&#xff0c;HKEX: 2391&#xff09;在“2023亚马逊云科技re:Inforce中国站”大会宣布与全球领先的云计算公司亚马逊云科技共同成立“联合安全实验室”&#xff0c;旨在加强IoT行业的安全合规能力与…...

Oracle21C--Windows卸载与安装

卸载方法&#xff1a; &#xff08;1&#xff09;WinR&#xff0c;输入services.msc,打开服务&#xff0c;把Oracle相关的服务全部停止运行&#xff08;重要&#xff09; &#xff08;2&#xff09;WinR&#xff0c;输入regedit&#xff0c;打开注册表&#xff0c;删除Oracle开…...

关于 MySQL、PostgresSQL、Mariadb 数据库2038千年虫问题

MySQL 测试时间&#xff1a;2023-8 启动MySQL服务后&#xff0c;将系统时间调制2038年01月19日03时14分07秒之后的日期&#xff0c;发现MySQL服务自动停止。 根据最新的MySQL源码&#xff08;mysql-8.1.0&#xff09;分析&#xff0c;sql/sql_parse.cc中依然存在2038年千年虫…...

Linux - Docker 安装使用 常用命令 教程

Docker 官方文档地址: Get Started | Docker 中文参考手册: https://docker_practice.gitee.io/zh-cn/ 1.什么是 Docker 1.1 官方定义 最新官网首页 # 1.官方介绍 - We have a complete container solution for you - no matter who you are and where you are on your contain…...

AtCoder Beginner Contest 318 G - Typical Path Problem 题解

G - Typical Path Problem 题目大意 给定一张 N N N 个点、 M M M 条边的简单无向图 G G G 和三个整数 A , B , C A,B,C A,B,C。 是否存在一条从顶点 A A A 到 C C C&#xff0c;且经过 B B B 的简单路径&#xff1f; 数据范围&#xff1a; 3 ≤ N ≤ 2 1 0 5 3\le …...

21.4 CSS 盒子模型

1. 边框样式 border-style属性: 指定元素的边框样式.常用属性值: - none: 无边框(默认值). - solid: 实线边框. - dotted: 点状边框. - dashed: 虚线边框. - double: 双线边框. - groove: 凹槽状边框. - ridge: 脊状边框. - inset: 内阴影边框. - outset: 外阴影边框.这些值可…...

MybatisPlus入门

MybatisPlus入门 1.MyBatis-Plus1.1 ORM介绍1.2 MyBatis-Plus介绍 2.代码链接数据库2.1 创建项目2.2 添加依赖2.3 链接数据库2.3.1 准备数据库2.3.2 链接数据库2.3.3 创建实体类 2.4 创建Mapper层2.5 创建Controller层2.6 浏览器访问测试 MybatisPlus官方网站&#xff1a; 官网…...

飞腾平台芯片测试固件(SFW)和开机启动log

一、说两句 最近公司飞腾产品越来越多了&#xff0c;FT-2000/4的D2000的X100的&#xff0c;最近又新出了E2000。越来越多新来的小孩儿开始加入到飞腾的调测试中&#xff0c;那么在他们实际的调试中会遇到很多的问题。在固件启动阶段有的板卡会有一些异常&#xff0c;有时我们需…...

【大数据实训】基于Hive的北京市天气系统分析报告(二)

博主介绍&#xff1a;✌全网粉丝6W,csdn特邀作者、博客专家、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于大数据技术领域和毕业项目实战✌ &#x1f345;文末获取项目联系&#x1f345; 目录 1. 引言 1.1 项目背景 1 1.2 项目意义 1 2.…...

WPF列表样式

WPF的数据绑定系统自动生成列表项对象&#xff0c;为单个项应用所需的样式不是很容易。解决方案是ItemContainerStyle 属性。如果设置了ItemContainerStyle 属性&#xff0c;当创建列表项时&#xff0c;列表控件会将其向下传递给每个项。对于ListBox控件&#xff0c;每个项有Li…...

Android逆向学习(二)vscode进行双开与图标修改

Android逆向学习&#xff08;二&#xff09;vscode进行双开与图标修改 写在前面 这其实应该还是吾爱的第一个作业&#xff0c;但是写完上一个博客的时候已经比较晚了&#xff0c;如果继续敲机械键盘吵到室友&#xff0c;我怕我看不到明天的太阳&#xff0c;所以我决定分成两篇…...

一个基于YAPI接口生产代码的开源工具

前后端分离的开发模式是一种趋势&#xff0c;但如果缺少好的开发工具跟管理模式&#xff0c;会使得前后端开发人员相互等待&#xff0c;扯皮等问题。从而影响项目的交付进度。 通过实践摸索&#xff0c;YAPI是一款很适合前后端分离开发的协助工具。它以项目为维度&#xff0c;可…...

Redis 缓存穿透击穿和雪崩

一、说明 Redis 缓存的使用&#xff0c;极大的提升了应用程序的性能和效率&#xff0c;特别是数据查询方面。但同时&#xff0c;它也带来了一些问题。其中&#xff0c;最要害的问题&#xff0c;就是数据的一致性问题&#xff0c;从严格意义上讲&#xff0c;这个问题无解。如果对…...

在windows上配置ninja环境

ninja使用并行任务来编译工程&#xff0c;比cmake编译快了一个数量级&#xff0c;是谷歌在2010年为了提高cmake的编译速度而开发一款编译工具。下面介绍在windows上配置ninja环境。 1 下载ninja ninja官网地址&#xff1a; https://github.com/ninja-build/ninja/releases   …...

③matlab向量和矩阵

目录 手动输入数组 创建等间距向量 数组创建函数 手动输入数组 1.背景 单个称为标量的数值实际上是一个 11 数组&#xff0c;也即它包含 1 行 1 列。 任务 创建一个名为 x 并且值为 4 的变量。 2.您可以使用方括号创建包含多个元素的数组。 x [3 5] x 3 5 任务 …...

一、了解[mysql]索引底层结构和算法

目录 一、索引1.索引的本质2.mysql的索引结构 二、存储引擎1.MyISAM2.InnoDB3.为什么建议InnoDB表要建立主键并且推荐int类型自增&#xff1f;4.innodb的主键索引和非主键索引&#xff08;二级索引&#xff09;区别5.联合索引 一、索引 1.索引的本质 索引:帮助mysql高效获取数…...

DockerFile常用命令

以下是常见的Dockerfile命令&#xff1a; FROM&#xff1a;FROM命令用于指定基础镜像。基础镜像是构建镜像的起点。例如&#xff0c;FROM ubuntu:latest表示使用最新版本的Ubuntu作为基础镜像。 MAINTAINER&#xff1a;MAINTAINER命令用于指定镜像的维护者信息。一般格式为&am…...

Android 动画之插值器PathInterpolator

Android 的View动画、属性动画都可以设置动画插值器&#xff0c;以此来实现不同的动画效果。 这篇文章 Android View动画整理 有介绍各种插值器的效果&#xff0c;这一篇专访 PathInterpolator 。 参考官网 添加曲线动作 &#xff0c; PathInterpolator 基于 贝塞尔曲线 或 …...

递归学习(转载)

转载至 https://www.cnblogs.com/king-lps/p/10748535.html 为避免原文丢失&#xff0c;因此原文转载作者【三年一梦】的帖子 前言 相信不少同学和我一样&#xff0c;在刚学完数据结构后开始刷算法题时&#xff0c;遇到递归的问题总是很头疼&#xff0c;而一看解答&#xff0c…...

python接口自动化(二)--什么是接口测试、为什么要做接口测试(详解)

简介 上一篇和大家一起科普扫盲接口后&#xff0c;知道什么是接口&#xff0c;接口类型等&#xff0c;对其有了大致了解之后&#xff0c;我们就回到主题-接口测试。 什么是接口测试 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各…...

HashMap源码阅读(一)

HashMap继承抽象类AbstractMap&#xff0c;AbstractMap抽象类实现了Map接口 一、HashMap中的静态常量 //默认初始容量 static final int DEFAULT_INITIAL_CAPACITY 1 << 4; // aka 16 //最大长度 static final int MAXIMUM_CAPACITY 1 << 30; //负载因子&#…...

C语言:动态内存(一篇拿捏动态内存!)

目录 学习目标&#xff1a; 为什么存在动态内存分配 动态内存函数&#xff1a; 1. malloc 和 free 2. calloc 3. realloc 常见的动态内存错误&#xff1a; 1. 对NULL指针的解引用操作 2. 对动态开辟空间的越界访问 3. 对非动态开辟内存使用free释放 4. 使用free释…...

Lua - 替换字符串中的特殊字符

//替换指定串 s string.gsub("Lua is good", "good", "bad") print(s) --> Lua is bad//替换特殊字符 a "我们使用$"; b string.gsub(a, "%$", "RMB"); print(b) --> 我们使用RMB//替换反斜杠 path …...

按钮控件之3---QRadioButton 单选按钮/单选框控件

本文详细的介绍了QRadioButton控件的各种操作&#xff0c;例如&#xff1a;QRadioButton分组、默认选中、禁用启用、重置样式等操作。 一、QRadioButton部件提供了一个带有文本标签的单选框&#xff08;单选按钮&#xff09;。QRadioButton是一个可以切换选中&#xff08;chec…...

基于STM32设计的游戏姿态数据手套

基于STM32设计的游戏姿态数据手套 一、项目背景 随着虚拟现实技术的发展,人机交互越来越朝着多通道、自然化的方向发展,由原来的以机器为中心向以人为中心发展。按照行业通用用途设计的高端数据手套,可以用于测量人手指动作,如搓捻、对掌等动作,广泛应用于人手的运动捕捉…...

react跳转页面redux数据被清除

关键代码如下&#xff0c;页面中有根据redux中state展示的数据&#xff0c;然后在组件卸载的时候会清空redux中存的数据&#xff0c;点击a标签可以打开新的标签页&#xff0c;如下代码会在打开新的标签页&#xff0c;组件卸载&#xff0c;清空redux数据&#xff0c;页面展示的也…...