This commit is contained in:
Mr.jiang 2024-07-23 15:42:42 +08:00
parent 3ec69bf011
commit d72daf3a20
16 changed files with 2023 additions and 2691 deletions

View File

@ -3,7 +3,7 @@
<view class="top"> <view class="top">
<view class="top_left"> <view class="top_left">
<img class="user_avatar" :src="data.user_avatar" /> <img class="user_avatar" :src="data.user_avatar" />
<uni-tag <!-- <uni-tag
v-if="data.owner" v-if="data.owner"
class="tag" class="tag"
type="primary" type="primary"
@ -11,11 +11,15 @@
text="作者" text="作者"
size="mini" size="mini"
circle circle
/> /> -->
<span class="user_name">{{ data.user_name }}</span> <view class="top_left_time">
<span class="user_name">{{ cReplyName }}</span> <span class="user_name">{{ data.user_name }}</span>
<span class="create_time" style="color: #fff;">{{ data.create_time }}</span>
</view>
<!-- <span class="user_name">{{ cReplyName }}</span> -->
</view> </view>
<view class="top_right" @tap="likeClick(data)"> <!-- <view class="top_right" @tap="likeClick(data)">
<span :class="[data.is_like ? 'active' : '', 'like_count']">{{ <span :class="[data.is_like ? 'active' : '', 'like_count']">{{
cLikeCount cLikeCount
}}</span> }}</span>
@ -31,25 +35,25 @@
size="24" size="24"
color="#999" color="#999"
></uni-icons> ></uni-icons>
</view> </view> -->
</view> </view>
<view class="content" @tap="replyClick(data)"> <view class="content" @tap="replyClick(data)">
{{ c_content }} {{ c_content }}
<span <!-- <span
class="shrink" class="shrink"
v-if="isShrink" v-if="isShrink"
@tap.stop="expandContentFun(data.user_content)" @tap.stop="expandContentFun(data.user_content)"
>...展开</span >...展开</span
> > -->
</view> </view>
<view class="bottom"> <view class="bottom">
<span class="create_time">{{ data.create_time }}</span> <!-- <span class="create_time">{{ data.create_time }}</span> -->
<span <!-- <span
v-if="data.owner" v-if="data.owner"
class="delete" class="delete"
@tap="deleteClick(data)" @tap="deleteClick(data)"
>删除</span >删除</span
> > -->
<!-- <span v-else class="reply" @tap="replyClick(data)" <!-- <span v-else class="reply" @tap="replyClick(data)"
>回复</span> --> >回复</span> -->
</view> </view>
@ -86,9 +90,6 @@ export default {
: this.data.like_count; : this.data.like_count;
} }
}, },
mounted() {
console.log("回复名字为:" ,this.data);
},
methods: { methods: {
// //
expandContentFun() { expandContentFun() {
@ -126,6 +127,13 @@ export default {
text-overflow: ellipsis; // text-overflow: ellipsis; //
} }
//////////////////////// ////////////////////////
.top_left_time{
display: flex;
flex-direction: row;
align-items: baseline;
justify-content: space-between;
width: 100%;
}
.comment_item { .comment_item {
font-size: 28rpx; font-size: 28rpx;
.top { .top {
@ -135,6 +143,7 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
overflow: hidden; overflow: hidden;
width: 100%;
.user_avatar { .user_avatar {
width: 68rpx; width: 68rpx;
height: 68rpx; height: 68rpx;
@ -163,9 +172,9 @@ export default {
.content { .content {
padding: 10rpx; padding: 10rpx;
margin-left: 70rpx; margin-left: 70rpx;
color: $uni-text-color; color: #fff;
&:active { &:active {
background-color: $uni-bg-color-hover; // background-color: $uni-bg-color-hover;
} }
.shrink { .shrink {
padding: 20rpx 20rpx 20rpx 0rpx; padding: 20rpx 20rpx 20rpx 0rpx;

View File

@ -1,400 +1,473 @@
<template> <template>
<view>
<view class="c_total">评论 {{ tableTotal }}</view> <scroll-view scroll-y="true" class="scroll-Y" @scrolltolower="loadMore">
<template v-if="dataList && dataList.length"> <!-- <view class="c_total">评论 {{ tableTotal }}</view> -->
<view class="c_comment" v-for="(item1, index1) in dataList" :key="item1.id"> <template v-if="dataList && dataList.length">
<!-- 一级评论 --> <view class="c_comment" v-for="(item1, index1) in dataList" :key="item1.id">
<CommonComp <!-- 一级评论 -->
:data="item1" <CommonComp :data="item1" />
@likeClick="() => likeClick({ item1, index1 })" <!-- 下边三个方法是 一级评论点击回复 -->
@replyClick="() => replyClick({ item1, index1 })" <!-- @likeClick="() => likeClick({ item1, index1 })"
@deleteClick="() => deleteClick({ item1, index1 })" @replyClick="() => replyClick({ item1, index1 })"
/> @deleteClick="() => deleteClick({ item1, index1 })" -->
<view <view class="children_item" v-if="item1.children && item1.children.length">
class="children_item" <!-- 二级评论 -->
v-if="item1.children && item1.children.length" <CommonComp v-for="(item2, index2) in item1.childrenShow" :key="item2.id" :data="item2"
> :pData="item1" />
<!-- 二级评论 --> <!-- 下边三个方法是 二级评论点击回复 -->
<CommonComp <!-- @likeClick="() => likeClick({ item1, index1, item2, index2 })"
v-for="(item2, index2) in item1.childrenShow" @replyClick="() => replyClick({ item1, index1, item2, index2 })"
:key="item2.id" @deleteClick="() => deleteClick({ item1, index1, item2, index2 })" -->
:data="item2" <!-- 展开折叠的二级评论 -->
:pData="item1" <view class="expand_reply" v-if="expandTxtShow({ item1, index1 })"
@likeClick="() => likeClick({ item1, index1, item2, index2 })" @tap="() => expandReplyFun({ item1, index1 })">
@replyClick="() => replyClick({ item1, index1, item2, index2 })" <span class="txt">
@deleteClick="() => deleteClick({ item1, index1, item2, index2 })" 展开{{ item1.children.length - item1.childrenShow.length }}条回复
/> </span>
<!-- 展开折叠的二级评论 --> <uni-icons type="down" size="24" color="#007aff"></uni-icons>
<view </view>
class="expand_reply" </view>
v-if="expandTxtShow({ item1, index1 })" </view>
@tap="() => expandReplyFun({ item1, index1 })" </template>
> <!-- 空盒子 -->
<span class="txt"> <view class="empty_box" v-else>
展开{{ item1.children.length - item1.childrenShow.length }}条回复 <uni-icons type="chatboxes" size="36" color="#c0c0c0"></uni-icons>
</span> <view>
<uni-icons type="down" size="24" color="#007aff"></uni-icons> <span class="txt"> 这里是一片荒草地, </span>
</view> <span class="txt click" @click="() => newCommentFun()">说点什么...</span>
</view> </view>
</view> </view>
</template> <!-- 评论弹窗 -->
<!-- 空盒子 --> <uni-popup ref="cPopupRef" type="bottom" @change="popChange">
<view class="empty_box" v-else> <view class="c_popup_box">
<uni-icons type="chatboxes" size="36" color="#c0c0c0"></uni-icons> <view class="reply_text">
<view> <template v-if="Object.keys(replyTemp).length">
<span class="txt"> 这里是一片荒草地, </span> <span class="text_aid">回复给</span>
<span class="txt click" @click="() => newCommentFun()">说点什么...</span> <span class="text_main">{{
</view>
</view>
<!-- 评论弹窗 -->
<uni-popup ref="cPopupRef" type="bottom" @change="popChange">
<view class="c_popup_box">
<view class="reply_text">
<template v-if="Object.keys(replyTemp).length">
<span class="text_aid">回复给</span>
<span class="text_main">{{
replyTemp.item1.item2 replyTemp.item1.item2
? replyTemp.item1.item2.user_name ? replyTemp.item1.item2.user_name
: replyTemp.item1.item1.user_name : replyTemp.item1.item1.user_name
}}</span> }}</span>
</template> </template>
<span v-else class="text_main">发表新评论</span> <span v-else class="text_main">发表新评论</span>
</view> </view>
<view class="content"> <view class="content">
<view class="text_area"> <view class="text_area">
<uni-easyinput <uni-easyinput class="text_area" type="textarea" v-model="commentValue"
class="text_area" :placeholder="commentPlaceholder" :focus="focus" trim autoHeight
type="textarea" maxlength="300"></uni-easyinput>
v-model="commentValue" </view>
:placeholder="commentPlaceholder" <view class="send_btn" @tap="() => sendClick()">发送</view>
:focus="focus" </view>
trim </view>
autoHeight </uni-popup>
maxlength="300" <!-- 删除弹窗 -->
></uni-easyinput> <uni-popup ref="delPopupRef" type="dialog">
</view> <uni-popup-dialog mode="base" title="" content="确定删除这条评论吗?" :before-close="true" @close="delCloseFun"
<view class="send_btn" @tap="() => sendClick()">发送</view> @confirm="delConfirmFun"></uni-popup-dialog>
</view> </uni-popup>
</view> </scroll-view>
</uni-popup>
<!-- 删除弹窗 -->
<uni-popup ref="delPopupRef" type="dialog">
<uni-popup-dialog
mode="base"
title=""
content="确定删除这条评论吗?"
:before-close="true"
@close="delCloseFun"
@confirm="delConfirmFun"
></uni-popup-dialog>
</uni-popup>
</view>
</template> </template>
<script> <script>
import CommonComp from "./componets/common"; import CommonComp from "./componets/common";
export default { export default {
components: { components: {
CommonComp CommonComp
}, },
props: { props: {
userInfo: { userInfo: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
}, },
tableData: { tableData: {
type: Array, type: Array,
default: () => [] default: () => []
}, },
tableTotal: { tableTotal: {
type: Number, type: Number,
default: 0 default: 0
}, },
deleteMode: { deleteMode: {
type: String, type: String,
default: "all" default: "all"
} }
}, },
data() { data() {
return { return {
dataList: [], isLoading: false, //
replyTemp: {}, dataList: [],
isNewComment: false, replyTemp: {},
focus: false, isNewComment: false,
commentValue: "", focus: false,
commentPlaceholder: "说点什么...", commentValue: "",
delTemp: {}, commentPlaceholder: "说点什么...",
index:0, delTemp: {},
}; index: 0,
}, };
watch: { },
tableData: { watch: {
handler(newVal) { tableData: {
if (newVal.length !== this.dataList.length) { handler(newVal) {
this.dataList = this.treeTransForm(newVal); if (newVal.length !== this.dataList.length) {
console.log("this.dataList:",this.dataList); this.dataList = this.treeTransForm(newVal);
} console.log("this.dataList:", this.dataList);
}, }
deep: true, },
immediate: true deep: true,
} immediate: true
}, }
methods: { },
treeTransForm(data) { onPageScroll : function(e) { //nvuebindingx
let newData = JSON.parse(JSON.stringify(data)); console.log("滚动距离为:" + e.scrollTop);
let result = []; },
let map = {}; methods: {
newData.forEach((item, i) => { loadMore() {
item.owner = item.id === this.userInfo.id; if (this.isLoading) return;
map[item.id] = item; this.isLoading = true;
}); if(this.openLoadMore){
newData.forEach((item) => { this.$emit("loadMore")
let parent = map[item.parent_id]; }
if (parent) { console.log(111)
(parent.children || (parent.children = [])).push(item); //
if (parent.children.length === 1) { // setTimeout(() => {
(parent.childrenShow = []).push(item); // const moreData = [...Array(20).keys()].map(i => `Item ${this.list.length + i + 1}`);
} // this.list.push(...moreData);
} else { // this.isLoading = false;
result.push(item); // }, 1000);
} },
}); treeTransForm(data) {
return result; let newData = JSON.parse(JSON.stringify(data));
}, let result = [];
setLike(item) { let map = {};
item.is_like = !item.is_like; newData.forEach((item, i) => {
item.like_count = item.is_like ? item.like_count + 1 : item.like_count - 1; item.owner = item.id === this.userInfo.id;
}, map[item.id] = item;
likeClick({ item1, index1, item2, index2 }) { });
let item = item2 || item1; newData.forEach((item) => {
this.setLike(item); let parent = map[item.parent_id];
this.$emit("likeFun", { params: item }, (res) => { if (parent) {
this.setLike(item); (parent.children || (parent.children = [])).push(item);
}); if (parent.children.length === 1) {
}, (parent.childrenShow = []).push(item);
replyClick(item1, index1, item2, index2) { }
this.replyTemp = JSON.parse(JSON.stringify({ item1, index1, item2, index2 })); } else {
console.log(this.replyTemp,"==========="); result.push(item);
this.$refs.cPopupRef.open(); }
}, });
newCommentFun() { return result;
this.isNewComment = true; },
this.$refs.cPopupRef.open(); setLike(item) {
}, item.is_like = !item.is_like;
popChange(e) { item.like_count = item.is_like ? item.like_count + 1 : item.like_count - 1;
if (!e.show) { },
this.commentValue = ""; likeClick({
this.replyTemp = {}; item1,
this.isNewComment = false; index1,
} item2,
this.focus = e.show; index2
}, }) {
sendClick() { let item = item2 || item1;
let { item1, index1, item2, index2 } = this.replyTemp; this.setLike(item);
let item = item2 || item1; this.$emit("likeFun", {
console.log(item); params: item
let params = {}; }, (res) => {
if (this.isNewComment) { this.setLike(item);
params.id = Math.random(); });
params.parent_id = null; },
params.reply_id = null; replyClick(item1, index1, item2, index2) {
params.reply_name = null; this.replyTemp = JSON.parse(JSON.stringify({
} else { item1,
params.id= Math.random(), index1,
params.parent_id = item.item1?.parent_id ?? item.item1.id, item2,
params.reply_id = item.item1.id, index2
params.reply_name = item.item2 ? item.item2.user_name : item.item1.user_name }));
console.log(this.replyTemp, "===========");
this.$refs.cPopupRef.open();
},
newCommentFun() {
this.isNewComment = true;
this.$refs.cPopupRef.open();
},
popChange(e) {
if (!e.show) {
this.commentValue = "";
this.replyTemp = {};
this.isNewComment = false;
}
this.focus = e.show;
},
sendClick() {
let {
item1,
index1,
item2,
index2
} = this.replyTemp;
let item = item2 || item1;
console.log('item=====', item);
let params = {};
if (this.isNewComment) {
params.id = this.tableData.id;
params.parent_id = this.tableData.parent_id;
params.reply_id = this.tableData.reply_id;
params.reply_name = this.tableData.reply_name;
} else {
params.id = this.tableData.id,
params.parent_id = item.item1?.parent_id ?? item.item1.id,
params.reply_id = item.item1.id,
params.reply_name = item.item2 ? item.item2.user_name : item.item1.user_name
} }
params = { params = {
...params, ...params,
user_name: this.userInfo.user_name, user_name: this.userInfo.user_name,
user_avatar: this.userInfo.user_avatar, user_avatar: this.userInfo.user_avatar,
user_content: this.commentValue, user_content: this.commentValue,
is_like: false, is_like: false,
like_count: 0, like_count: 0,
create_time: "刚刚", create_time: "刚刚",
owner: true owner: true
}; };
console.log("params: ",params); uni.showLoading({
title: "正在发送",
uni.showLoading({ mask: true
title: "正在发送", });
mask: true this.$emit("replyFun", {
}); params
this.$emit("replyFun", { params }, (res) => { }, (res) => {
uni.hideLoading(); uni.hideLoading();
params = { ...params, id: res.id }; params = {
if (this.isNewComment) { ...params,
this.dataList.push(params); id: res.id
} else { };
console.log(this.dataList); if (this.isNewComment) {
let c_data = this.dataList[item.index1]; this.dataList.push(params);
(c_data.children || (c_data.children = [])).push(params); } else {
if ( console.log(this.dataList);
c_data.children.length === (c_data.childrenShow || (c_data.childrenShow = [])).length + 1 let c_data = this.dataList[item.index1];
) { (c_data.children || (c_data.children = [])).push(params);
c_data.childrenShow.push(params); if (
} c_data.children.length === (c_data.childrenShow || (c_data.childrenShow = [])).length +
} 1
this.$emit("update:tableTotal", this.tableTotal + 1); ) {
this.$refs.cPopupRef.close(); c_data.childrenShow.push(params);
}); }
}, }
deleteClick(item1, index1, item2, index2) { this.$emit("update:tableTotal", this.tableTotal + 1);
this.delTemp = JSON.parse(JSON.stringify({ item1, index1, item2, index2 })); this.$refs.cPopupRef.close();
this.$refs.delPopupRef.open(); });
}, },
delCloseFun() { deleteClick(item1, index1, item2, index2) {
this.delTemp = {}; this.delTemp = JSON.parse(JSON.stringify({
this.$refs.delPopupRef.close(); item1,
}, index1,
delConfirmFun({ item1, index1, item2, index2 } = this.delTemp) { item2,
let c_data = this.dataList[index1]; index2
uni.showLoading({ }));
title: "正在删除", this.$refs.delPopupRef.open();
mask: true },
}); delCloseFun() {
if (index2 >= 0) { this.delTemp = {};
this.$emit("deleteFun", { params: [c_data.children[index2].id] }, (res) => { this.$refs.delPopupRef.close();
uni.hideLoading(); },
this.$emit("update:tableTotal", this.tableTotal - 1); delConfirmFun({
c_data.children.splice(index2, 1); item1,
c_data.childrenShow.splice(index2, 1); index1,
}); item2,
} else { index2
if (c_data.children && c_data.children.length) { } = this.delTemp) {
switch (this.deleteMode) { let c_data = this.dataList[index1];
case "bind": uni.showLoading({
c_data.user_content = "当前评论内容已被移除"; title: "正在删除",
break; mask: true
case "only": });
this.$emit("deleteFun", { if (index2 >= 0) {
mode: this.deleteMode, this.$emit("deleteFun", {
params: [c_data.id] params: [c_data.children[index2].id]
}, (res) => { }, (res) => {
uni.hideLoading(); uni.hideLoading();
this.$emit("update:tableTotal", this.tableTotal - c_data.children.length + 1); this.$emit("update:tableTotal", this.tableTotal - 1);
this.dataList.splice(index1, 1); c_data.children.splice(index2, 1);
}); c_data.childrenShow.splice(index2, 1);
break; });
default: } else {
let delIdArr = [c_data.id]; if (c_data.children && c_data.children.length) {
c_data.children.forEach((_, i) => { switch (this.deleteMode) {
delIdArr.push(_.id); case "bind":
}); c_data.user_content = "当前评论内容已被移除";
this.$emit("deleteFun", { params: delIdArr, mode: this.deleteMode }, (res) => { break;
uni.hideLoading(); case "only":
this.$emit("update:tableTotal", this.tableTotal - c_data.children.length + 1); this.$emit("deleteFun", {
this.dataList.splice(index1, 1); mode: this.deleteMode,
}); params: [c_data.id]
break; }, (res) => {
} uni.hideLoading();
} else { this.$emit("update:tableTotal", this.tableTotal - c_data.children.length + 1);
this.$emit("deleteFun", { params: [c_data.id] }, (res) => { this.dataList.splice(index1, 1);
uni.hideLoading(); });
this.$emit("update:tableTotal", this.tableTotal - 1); break;
this.dataList.splice(index1, 1); default:
}); let delIdArr = [c_data.id];
} c_data.children.forEach((_, i) => {
} delIdArr.push(_.id);
this.delCloseFun(); });
}, this.$emit("deleteFun", {
expandTxtShow(item1, index1) { params: delIdArr,
return ( mode: this.deleteMode
item1.childrenShow && }, (res) => {
item1.childrenShow.length && uni.hideLoading();
item1.children.length - item1.childrenShow.length this.$emit("update:tableTotal", this.tableTotal - c_data.children.length + 1);
); this.dataList.splice(index1, 1);
}, });
expandReplyFun(item1, index1) { break;
let csLen = this.dataList[index1].childrenShow.length; }
this.dataList[index1].childrenShow.push( } else {
...this.dataList[index1].children.slice(csLen, csLen + 6) this.$emit("deleteFun", {
); params: [c_data.id]
} }, (res) => {
} uni.hideLoading();
}; this.$emit("update:tableTotal", this.tableTotal - 1);
this.dataList.splice(index1, 1);
});
}
}
this.delCloseFun();
},
expandTxtShow(item1, index1) {
return (
item1.childrenShow &&
item1.childrenShow.length &&
item1.children.length - item1.childrenShow.length
);
},
expandReplyFun(item1, index1) {
let csLen = this.dataList[index1].childrenShow.length;
this.dataList[index1].childrenShow.push(
...this.dataList[index1].children.slice(csLen, csLen + 6)
);
}
}
};
</script> </script>
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
//////////////////////// ////////////////////////
.center { .center {
display: flex; display: flex;
align-items: center; align-items: center;
} }
////////////////////////
.c_total {
padding: 20rpx 30rpx 0 30rpx;
font-size: 28rpx;
}
.empty_box {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
padding: 150rpx 10rpx;
font-size: 28rpx;
.txt {
color: $uni-text-color-disable;
}
.click {
color: $uni-color-primary;
}
}
.c_comment {
padding: 20rpx 30rpx;
font-size: 28rpx;
.children_item { ////////////////////////
padding: 20rpx 30rpx; .scroll-Y {
margin-top: 10rpx; height: 940rpx;
margin-left: 80rpx; }
// background-color: $uni-bg-color-grey; .scroll-view_H {
.expand_reply { white-space: nowrap;
margin-top: 10rpx; width: 100%;
margin-left: 80rpx; }
.txt { .scroll-view-item {
font-weight: 600; height: 300rpx;
color: $uni-color-primary; line-height: 300rpx;
} text-align: center;
} font-size: 36rpx;
} }
} .scroll-view-item_H {
.c_popup_box { display: inline-block;
background-color: #fff; width: 100%;
.reply_text { height: 300rpx;
@extend .center; line-height: 300rpx;
padding: 20rpx 20rpx 0 20rpx; text-align: center;
font-size: 26rpx; font-size: 36rpx;
.text_aid { }
color: $uni-text-color-grey; // .template-view {
margin-right: 5rpx; // height: 430px;
} // overflow: auto;
.text_main { // }
}
} .c_total {
.content { padding: 20rpx 30rpx 0 30rpx;
@extend .center; font-size: 28rpx;
.text_area { color: #fff;
flex: 1; }
padding: 20rpx;
} .empty_box {
.send_btn { display: flex;
@extend .center; justify-content: center;
justify-content: center; align-items: center;
width: 120rpx; flex-direction: column;
height: 60rpx; padding: 150rpx 10rpx;
border-radius: 20rpx; font-size: 28rpx;
font-size: 28rpx;
color: #fff; .txt {
background-color: $uni-color-primary; color: $uni-text-color-disable;
margin-right: 20rpx; }
}
} .click {
} color: $uni-color-primary;
}
}
.c_comment {
padding: 20rpx 30rpx;
font-size: 28rpx;
.children_item {
padding: 20rpx 30rpx;
margin-top: 10rpx;
margin-left: 80rpx;
// background-color: $uni-bg-color-grey;
.expand_reply {
margin-top: 10rpx;
margin-left: 80rpx;
.txt {
font-weight: 600;
color: $uni-color-primary;
}
}
}
}
.c_popup_box {
background-color: #fff;
.reply_text {
@extend .center;
padding: 20rpx 20rpx 0 20rpx;
font-size: 26rpx;
.text_aid {
color: $uni-text-color-grey;
margin-right: 5rpx;
}
.text_main {}
}
.content {
@extend .center;
.text_area {
flex: 1;
padding: 20rpx;
}
.send_btn {
@extend .center;
justify-content: center;
width: 120rpx;
height: 60rpx;
border-radius: 20rpx;
font-size: 28rpx;
color: #fff;
background-color: $uni-color-primary;
margin-right: 20rpx;
}
}
}
</style> </style>

File diff suppressed because it is too large Load Diff

View File

@ -47,6 +47,7 @@
"style": { "style": {
"navigationBarTitleText": "视频圈", "navigationBarTitleText": "视频圈",
"enablePullDownRefresh": true, "enablePullDownRefresh": true,
"onReachBottomDistance":200,
"navigationStyle": "custom", "navigationStyle": "custom",
"app-plus": { "app-plus": {
"titleNView": false "titleNView": false

View File

@ -191,7 +191,7 @@
</view> </view>
</view> </view>
</view> </view>
<view class="body-view" style="display: none;"> <view class="body-view">
<!-- 使用scroll-view实现tabs滑动切换 --> <!-- 使用scroll-view实现tabs滑动切换 -->
<scroll-view class="top-menu-view" scroll-x="true" scroll-with-animation :scroll-left="scrollLeft"> <scroll-view class="top-menu-view" scroll-x="true" scroll-with-animation :scroll-left="scrollLeft">
<view class="menu-topic-view" v-for="(item,index) in tabs" :id="'tabNum'+item.id" :key="index" @click="swichMenu(index)"> <view class="menu-topic-view" v-for="(item,index) in tabs" :id="'tabNum'+item.id" :key="index" @click="swichMenu(index)">
@ -207,9 +207,23 @@
<swiper class="swiper-box-list" :current="currentTab" @change="swiperChange"> <swiper class="swiper-box-list" :current="currentTab" @change="swiperChange">
<swiper-item class="swiper-topic-list" v-for="item in swiperDateList" :key="item.id"> <swiper-item class="swiper-topic-list" v-for="item in swiperDateList" :key="item.id">
<view class="swiper-item-card"> <view class="swiper-item-card">
<view class="swiper-back-img"> <!-- <view class="swiper-back-img">
<image src="../../static/bofang.png" mode="widthFix"></image> <image src="../../static/bofang.png" mode="widthFix"></image>
</view> </view> -->
<video
:loop="true"
:controls="true"
:autoplay="false"
:http-cache="true"
:page-gesture="true"
:show-fullscreen-btn="true"
:show-loading="true"
:show-center-play-btn="true"
:enable-progress-gesture="true"
style="width: 100%;height: 162px;"
src="http://1.92.152.160/file/uploadPath/2024/07/18/3b23e6ea30fd2f2502b6a31334481143.mp4"
:poster="'http://1.92.152.160/file/uploadPath/2024/07/18/20240718170642301190.png'"
></video>
<view class="swiper-item"> <view class="swiper-item">
<span>{{item.name}}</span> <span>{{item.name}}</span>
<span>{{item.content}}</span> <span>{{item.content}}</span>
@ -1082,6 +1096,9 @@
</script> </script>
<style scoped> <style scoped>
.top-menu-view /deep/.uni-scroll-view-content{
justify-content: space-around;
}
.salogo{ .salogo{
width: 140rpx; width: 140rpx;
height: 36rpx; height: 36rpx;

View File

@ -1,756 +0,0 @@
<template>
<view>
<!--
注意这是 H5微信小程序界面请勿和 new_index.nvueindex.nvue 混用
1. new_index.nvueindex.nvue这两个是App页面
2. 另外data.js 是上一版本留下的假数据这一版改成了 URL 请求了如不需要可以删除也可作为后端请求参考
3. 请各位大神多多留手我已经把请求内存开到最大了
4. 视频 id 切记是字符串类型 -->
<image v-if="isShowAixin" src="@/static/img/index/aixining.png" :style="'position: fixed; margin-left: '+ aixinLeft +'px; margin-top: '+ aixinTop +'px; width: 70px; height: 65px; transform: rotate('+ Rotate +'deg);'"></image>
<swiper :style="'width: '+ windowWidth +'px; height: '+ windowHeight +'px; background-color: #000000;'" :vertical="true" @animationfinish="animationfinish" @change="change" :current="current" :indicator-dots="false" :duration="duration">
<swiper-item v-for="(list,index) in dataList" :key="index" style="height: 98%;">
<view v-if="Math.abs(k-index)<=1">
<view>
<!--
1.v-if用于控制视频在节点的渲染数
2.muted的默认值是 false代表默认是禁音视频的
3.http-cache默认开启视频缓存
4.poster封面方案一这里的封面默认处理存储在阿里云的视频
5.show-loading这里默认去掉播放转圈的标志
v-if="Math.abs(k-index)<=1"
-->
<video
v-if="isShow"
:id="list._id+''+index"
:loop="true"
:muted="list.isplay"
:controls="false"
:autoplay="true"
:http-cache="f"
:page-gesture="false"
:show-fullscreen-btn="false"
:show-loading="false"
:show-center-play-btn="false"
:enable-progress-gesture="false"
:src="list.src"
@ended="ended"
@click="tapVideoHover(list.state,$event)"
@timeupdate="timeupdate($event,index)"
:style="'width: '+ windowWidth +'px; height: '+ windowHeight +'px; background-color: #000000; z-index: 8;'"
:poster="list.src+'?x-oss-process=video/snapshot,t_100,f_jpg'"
></video>
<!--
1.这里是封面方案二这里的封面可以自定义
2.也在代码中做了批注两种方案可以共存不会相互影响
-->
<image
v-if="!list.playIng"
:src="list.src+'?x-oss-process=video/snapshot,t_100,f_jpg'"
:style="'width: '+ windowWidth +'px; height: '+ windowHeight +'px; position: absolute; z-index: 6;'"
mode="aspectFit"
></image>
</view>
<!-- 播放状态pause 的时候就会暂停 -->
<view class="videoHover" @click="tapVideoHover(list.state,$event)" @touchstart="touchstartHover" :style="'width: '+ windowWidth +'px; height: '+ windowHeight +'px;z-index:14;'">
<image v-if="list.state=='pause'" class="playState" src="@/static/img/index/play.png"></image>
</view>
<view class="userInfo">
<!-- 1.头像 -->
<image @click="tozuozhe" class="userAvatar" :src="list.href" mode="aspectFill"></image>
<!-- 2.点赞 -->
<view class="list-view" @click="cLike(list.like);" style="opacity: 0.9; margin-top: 17px;">
<image v-if="list.like" src="@/static/img/index/xin.png" style="width: 40px; height: 40px; position: absolute; right: 6px;"></image>
<image v-if="!list.like" src="@/static/img/index/xin-2.png" style="width: 40px; height: 40px; position: absolute; right: 6px;"></image>
<text style="color: #FFFFFF; margin-top: 5px; font-size: 14px; text-align: center; margin-top: 40px; font-weight: bold;" :class="{'likeNumActive':list.like}">{{list.like_n}}</text>
</view>
<!-- 3.评论 -->
<view class="comment list-view" @click="toComment(index)" style="opacity: 0.9; margin-top: 17px;">
<image src="@/static/img/index/liaotian-2.png" style="width: 35px; height: 35px; position: absolute; right: 7px;"></image>
<text style="color: #FFFFFF; margin-top: 5px; font-size: 14px; font-weight: bold; text-align: center; margin-top: 40px;">{{list.sms_n}}</text>
</view>
<!-- 4.分享 -->
<view class="list-view" @click="share" style="opacity: 0.9; margin-top: 17px;">
<image src="@/static/img/index/share-fill.png" style="width: 40px; height: 40px; position: absolute; right: 5px;"></image>
<text style="color: #FFFFFF; margin-top: 5px; font-size: 14px; text-align: center; font-weight: bold; margin-top: 40px;">分享</text>
</view>
<view class="list-view" @click="dealVoice" style="margin-top: 17px;">
<view style="width: 48px; height: 48px; border-radius: 50px; position: absolute; right: 2.5px;">
<image :style="'width: 48px; height: 48px; border-radius: 50px; transform: rotate('+ rotates +'deg);'" src="@/static/img/index/bfq.png" mode="aspectFill"></image>
<image v-if="showPlay" :style="'width: 30px; height: 30px; margin-top: 9px; margin-left: 9px; position: absolute; border-radius: 50px; transform: rotate('+ rotates +'deg);'" :src="list.href" mode="aspectFill"></image>
</view>
</view>
</view>
<!-- 最底下的文字部分 -->
<view class="content">
<text class="userName" :style="'width: '+ (windowWidth - 90) +'px;'">{{list.title}}</text><!-- i={{i}} -->
<text class="words" :style="'width: '+ (windowWidth - 90) +'px;'">{{list.msg}}-{{k+1}}</text><!-- k={{k}} -->
</view>
<!-- 进度条 -->
<view v-if="k === index" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend" :style="'width: '+ (windowWidth - (windowWidth*0.10)) +'px; margin-left: '+ (windowWidth * 0.05) +'px; height: 40px; position: absolute;bottom: 0px;margin-bottom: 6px;z-index: 14;'">
<!-- 不拖动情况下 -->
<view>
<!-- 1.底部背景进度条 -->
<view :style="'width: '+ (windowWidth - (windowWidth*0.10)) +'px; margin-top: 18px; height: 5px; border-radius: 10px; background-color: #999999; opacity: 0.6;'"></view>
<!-- 2.播放的进度条 -->
<view v-if="isTouch==false" :style="'width: '+ ((windowWidth - (windowWidth*0.10)) * progressBarPercent) +'px; position: absolute;top: 0; margin-top: 18px; height: 5px; border-radius: 10px; background-color: #e6e4e7; '"></view>
<!-- -->
<view v-if="isTouch==true" :style="'width: '+ (videoStartPositon + addPositon) +'px; position: absolute;top: 0; margin-top: 18px; height: 5px; border-radius: 10px; background-color: #e6e4e7; '"></view>
</view>
</view>
</view>
</swiper-item>
</swiper>
<uni-popup type="bottom" ref="pinglun" @touchmove.stop.prevent="moveHandle">
<view :style="'width: '+ windowWidth +'px; height: '+ (boxStyle.height/heightNum) +'px; background-color: #242424; border-top-left-radius: 10px; border-top-right-radius: 10px;'">
<!--
注意
deleteIOSHeight
deleteAndroidHeight
这两个参数用于控制评论等的高度
-->
<douyin-scrollview
:Width="windowWidth"
:Height="(boxStyle.height/1.23)"
:deleteIOSHeight="36"
:deleteAndroidHeight="15"
@closeScrollview="closeScrollview"
></douyin-scrollview>
</view>
</uni-popup>
</view>
</template>
<script>
// import userList from '../new_index/data.js'//
let audo = uni.createInnerAudioContext()
audo.loop = true
import douyinScrollview from '../../components/douyin-scrollview/douyin-scrollview.vue'
export default {
components:{
douyinScrollview
},
data() {
return {
windowWidth: 0,
windowHeight: 0,
platform: "",
model: "",
deleteHeight: 0,
dataList: [],
k: 0,
oldVideo: "",
voice: "",
timeout: "",
current: 0,
boxStyle:{//🌟💗
'height': 0,
'width': 0,
},
videoID: "",
isShow: false,
showPlay: false,//
rotates: 0,//
rotateTime: "",//
xrotats: "",
mpcleartime: "",
isClick: false,
changeTimeout: "",
mptime: 0,
mpstartTime: 0,
duration: 500,
// -- -- start
videoStartPositon: 0,
progressBarPercent: 0,
touchStartPosition: 0,
addPositon: 0,
timeduration: 0,
isTouch: false,
// -- -- end
// -
heightNum: 1.18,
//
touchNum: 0,
aixinLeft: 0,
aixinTop: 0,
isShowAixin: false,
Rotate: 0,
isShow1: false,//1
isShow2: false,//2 uni-popup
currents: 0,//01🌟💗
}
},
watch:{
async k(k,old_k){
// console.log(k, old_k)
this.progressBarPercent = 0;
// #ifndef MP
this.clearToTime();
// #endif
this.isShow = false
this.dataList[old_k].playIng = false//
this.dataList[old_k].isplay = true
this.dataList[old_k].state = 'pause'
console.log('预留第' + (old_k + 1) + '个视频:' + this.dataList[old_k]._id+''+old_k)
// 2.0
uni.createVideoContext(this.dataList[old_k]._id + '' + old_k,this).stop()//this.dataList[old_k]._id + '' + old_k old_k id
console.log('已经暂停 --> 第' + (old_k + 1) + '个视频~')//
this.dataList[k].state = 'play'
this.isShow = true
this.xrotats = setTimeout(()=>{
this.showPlay = true;
// #ifndef MP
this.rotateX();
// #endif
},200)
// #ifdef MP
//
clearTimeout(this.changeTimeout);
this.dataList[k].isplay = false
setTimeout(()=>{
this.dataList[k].playIng = true
},250)
if(this.mptime < 0.2){
this.changeTimeout = setTimeout(()=>{
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).play()
},1400)
} else {
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).play()
}
// #endif
// #ifdef H5
this.dataList[k].isplay = true
audo.src = this.dataList[k].src
if(this.isClick){
setTimeout(()=>{
if (typeof WeixinJSBridge == "undefined") {
setTimeout(()=>{
audo.play()
uni.createVideoContext(this.dataList[k]._id+''+k,this).seek(0)
uni.createVideoContext(this.dataList[k]._id+''+k,this).play()
setTimeout(()=>{
this.dataList[k].playIng = true
},650)
},500)
} else {
WeixinJSBridge.invoke('getNetworkType', {}, e => {
setTimeout(()=>{
audo.play()
uni.createVideoContext(this.dataList[k]._id+''+k,this).seek(0)
uni.createVideoContext(this.dataList[k]._id+''+k,this).play()
setTimeout(()=>{
this.dataList[k].playIng = true
},850)
},200)
})
}
},200)
} else {
audo.pause()
this.dataList[k].state = 'pause'
uni.createVideoContext(this.dataList[k]._id+''+k,this).seek(0)
uni.createVideoContext(this.dataList[k]._id+''+k,this).pause()
}
// #endif
var p = k+1;
console.log('预加载第' + (p + 1) + '个视频:' + this.dataList[p]._id+''+p)
}
},
onLoad() {
this.platform = uni.getSystemInfoSync().platform
this.model = uni.getSystemInfoSync().model
var model = this.model
if(this.platform == 'ios' && (model !== 'iPhone6' || model !== 'iPhone6s' || model !== 'iPhone7' || model !== 'iPhone8')){
this.deleteHeight = 0// tabbar
}
this.windowWidth = uni.getSystemInfoSync().windowWidth
this.windowHeight = uni.getSystemInfoSync().windowHeight
this.boxStyle.width = this.windowWidth + 'px'//px
this.boxStyle.height = this.windowHeight - this.deleteHeight;// tabbar
this.get() //
// #ifndef MP
this.rotateX();
// #endif
},
onShow(){
console.log('回到前台');
if(this.dataList.length !== 0){
// #ifdef MP
this.dataList[this.k].state = 'play';
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).play()
// #endif
// #ifdef H5
if(this.isClick){
this.dataList[this.k].state = 'play';
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).play()
audo.play()
}
// #endif
}
},
onHide(){
// #ifdef MP
this.dataList[this.k].state = 'pause';
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).pause()
// #endif
// #ifdef H5
if(this.isClick){
this.dataList[this.k].state = 'pause';
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).pause()
audo.pause()
}
// #endif
console.log('到后台');
},
methods: {
closeScrollview(){
//
this.$refs.pinglun.close('bottom');
},
onTabItemTaps() {
if (uni.getSystemInfoSync().platform == "ios") {
let UIImpactFeedbackGenerator = plus.ios.importClass('UIImpactFeedbackGenerator');
let impact = new UIImpactFeedbackGenerator();
impact.prepare();
impact.init(1);
impact.impactOccurred();
}
if (uni.getSystemInfoSync().platform == "android") {
uni.vibrateShort({
success: () => {
console.log('点击震动');
}
});
}
},
//
touchstartHover(event){
if(this.touchNum >= 1){
// console.log(' -- X'+ event.touches[0].screenX);
// console.log(' -- Y'+ event.touches[0].screenY);
this.aixinLeft = event.touches[0].screenX - 50;
this.aixinTop = event.touches[0].screenY - 50;
this.isShowAixin = true;
let max = 40; let min = -40;
this.Rotate = Math.floor(Math.random() * (max - min + 1)) + min;
setTimeout(()=>{
this.isShowAixin = false;
},700)
this.onTabItemTaps();
}
},
tozuozhe(){
this.currents = 1//
},
mpTouchend(){
this.mptime = (new Date()/1000) - this.mpstartTime;
},
mpTouchstart(){
this.mpstartTime = (new Date()/1000);
},
dealVoice(){
uni.showToast({
title: '处理声音',
icon: 'none'
})
},
clearToTime(){
//
for(let i=0;i<20;i++){
clearTimeout(this.rotateTime);
clearTimeout(this.xrotats);
this.showPlay = false;
this.rotates = 0;
}
},
clearTime(){
//
for(let i=0;i<20;i++){
clearTimeout(this.rotateTime);
clearTimeout(this.xrotats);
}
},
rotateX(){
// clearTimeout(this.rotateTime);
this.rotateTime = setTimeout(()=>{
this.rotateX();
this.showPlay = true;
this.rotates += 1;
},30)
},
ended(){
// 1.
// this.current = this.k+1
},
// ---- --- start
touchstart(e){
this.isTouch = true;
// #ifdef H5
if(this.isTouch == true){
this.addPositon = 0;
console.log("touchstart",this.windowWidth);
this.videoStartPositon = (this.windowWidth - (this.windowWidth*0.10)) * this.progressBarPercent;
this.touchStartPosition = e.changedTouches[0].clientX;
}
// #endif
// #ifdef MP
this.addPositon = 0;
this.videoStartPositon = (this.windowWidth - (this.windowWidth*0.10)) * this.progressBarPercent;
this.touchStartPosition = e.changedTouches[0].clientX;
// #endif
},
touchmove(e){
console.log("touchmove",e);
// #ifdef H5
if(this.isTouch == true){
let num = e.changedTouches[0].clientX - this.touchStartPosition;
if((this.videoStartPositon + num) <= (this.windowWidth - (this.windowWidth*0.10))) {
this.addPositon = e.changedTouches[0].clientX - this.touchStartPosition;
} else {
this.addPositon = 0;
this.videoStartPositon = (this.windowWidth - (this.windowWidth*0.10));
}
}
// #endif
// #ifdef MP
let num = e.changedTouches[0].clientX - this.touchStartPosition;
if((this.videoStartPositon + num) <= (this.windowWidth - (this.windowWidth*0.10))) {
this.addPositon = e.changedTouches[0].clientX - this.touchStartPosition;
} else {
this.addPositon = 0;
this.videoStartPositon = (this.windowWidth - (this.windowWidth*0.10));
}
// #endif
},
touchend(e){
// #ifdef H5
if(this.isClick){
let per = Number( (this.videoStartPositon+this.addPositon) / (this.windowWidth - (this.windowWidth*0.10)) );
let timeSubmit = parseInt( this.timeduration * per )
audo.seek(timeSubmit)
audo.play()
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).seek(timeSubmit)
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).play()
this.dataList[this.k].state = 'play'
setTimeout(()=>{
this.isTouch = false;
},500)
}
// #endif
// #ifdef MP
let per = Number( (this.videoStartPositon+this.addPositon) / (this.windowWidth - (this.windowWidth*0.10)) );
let timeSubmit = parseInt( this.timeduration * per )
audo.seek(timeSubmit)
audo.play()
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).seek(timeSubmit)
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).play()
setTimeout(()=>{
this.isTouch = false;
},500)
// #endif
},
timeupdate(event,index){
//
// console.log(event,index);
if(index === this.k){
this.timeduration = event.detail.duration;
this.progressBarPercent = parseFloat( Number( event.detail.currentTime / event.detail.duration ) );
}
},
// ---- --- ending
doubleLike(){
if(this.dataList[this.k].like == false){
this.dataList[this.k].like_n += 1;
this.dataList[this.k].like = true;
}
/*
点赞
*/
},
//&&
tapVideoHover(state,event){
this.dataList[this.k].isShowimage = false
this.dataList[this.k].isShowProgressBarTime = false
this.ProgressBarOpacity = 0.5
this.dotWidth = 0
console.log('state--',state);
// 1. --- start
this.touchNum++;
setTimeout(()=>{
if(this.touchNum == 1){
if(state=='play'||state=='continue'){
this.dataList[this.k].state = 'pause';
}else{
this.dataList[this.k].state = 'continue';
}
if(this.dataList[this.k].state == 'continue'){
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).play();//
this.clearTime();
setTimeout(()=>{
this.rotateX();
},50)
}
if(this.dataList[this.k].state == 'pause'){
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).pause();//
this.clearTime();
}
}
if(this.touchNum >= 2){
this.doubleLike();
}
this.touchNum = 0;
},200)
// --------------- ending
// 2. start
// if(state=='play'||state=='continue'){
// this.dataList[this.k].state = 'pause';
// }else{
// this.dataList[this.k].state = 'continue';
// }
// if(this.dataList[this.k].state == 'continue'){
// uni.createVideoContext(this.dataList[this.k]._id,this).play();//
// }
// if(this.dataList[this.k].state == 'pause'){
// uni.createVideoContext(this.dataList[this.k]._id,this).pause();//
// }
// --------------- ending
},
//&&
tapVideoHovers(state,event){
console.log('state--',state);
if(state=='play'||state=='continue'){
this.dataList[this.k].state = 'pause';
}else{
this.dataList[this.k].state = 'continue';
}
if(this.dataList[this.k].state == 'continue'){
this.isClick = true;
this.dataList[this.k].playIng = true
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).play();//
// #ifdef MP
this.dataList[this.k].isplay = false
// #endif
// #ifdef H5
audo.play()
// #endif
}
if(this.dataList[this.k].state == 'pause'){
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).pause();//
// #ifdef MP
this.dataList[this.k].isplay = true
// #endif
// #ifdef H5
audo.pause()
// #endif
}
},
change(event){
this.k = event.detail.current
},
animationfinish(event){
// 1. get()
if(this.k == this.dataList.length - 1){
this.GET()
}
},
//
GET(){
uni.request({
url: 'https://bdb24c6d-8c19-4f80-8e7e-c9c9f037f131.bspapp.com/video',
method: 'POST',
data:{
info: 'get_video'
},
success: (res) => {
var msg = res.data.data
// 2.
for (let i = 0; i < msg.length; i++) {
this.dataList.push(msg[i])
}
}
})
},
get(){
// 1.
// var msg = userList
uni.request({
url: 'https://bdb24c6d-8c19-4f80-8e7e-c9c9f037f131.bspapp.com/video',
method: 'POST',
data:{
info: 'get_video'
},
success: (res) => {
this.isShow = false;
var msg = res.data.data
// 2.
for (let i = 0; i < msg.length; i++) {
this.dataList.push(msg[i])
}
// 3.
setTimeout(()=>{
this.isShow = true;
// #ifdef H5
this.dataList[this.k].isplay = true
// #endif
// #ifdef MP
//
this.dataList[this.k].isplay = false
this.dataList[this.k].state = 'play'
// #endif
this.dataList[this.k].playIng = true
setTimeout(()=>{
// #ifdef H5
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).seek(0)
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).pause()
this.dataList[this.k].state = 'pause';
audo.src = this.dataList[this.k].src;
// #endif
// #ifdef MP
uni.createVideoContext(this.dataList[this.k]._id+''+this.k,this).play()
// #endif
},500)
},200)
this.videoID = this.dataList[this.k]._id
}
})
},
share(){
uni.showToast({
title: '分享',
icon: 'none'
})
},
toComment(index){
//
/*
1先加载缓冲
2获取当前视频 ID 信息
3🌟🌟🌟🌟重要🌟🌟🌟🌟
- 一定要记得看 index.vue 里面
uni.setStorageSync("user",this.peopleList[i]);
这个东西用于存储当前用户信息 插件里面会使用到这个东西
记得写一下
4打开评论
*/
uni.showToast({
title: '加载中...',
icon: 'none',
position: 'bottom',
duration: 300
})
uni.setStorageSync("videoID",this.dataList[index]._id);
this.videoID = this.dataList[index]._id;
this.$refs.pinglun.open('bottom')
},
cLike(sss){
this.dataList[this.k].like = !this.dataList[this.k].like
const video = this.dataList[this.k];
sss?video.like_n -= 1:video.like_n += 1;
}
}
}
</script>
<style scoped>
.list-view{
display: flex;
flex-direction: column;
align-items: center;
}
.container {background-color: #000000;}
.item {
/* width : 750rpx; */
background-color: #000000;
position: relative;
}
.videoHover{
position: absolute;
top: 0;
left: 0;
flex: 1;
background-color: rgba(0,0,0,0.1);
justify-content: center;
align-items: center;
display: flex;
/* border-style: dashed;
border-color: #DD524D;
border-width: 1px; */
}
.playState{
width: 160rpx;
height: 160rpx;
opacity: 0.2;
}
.userInfo{
position: absolute;
bottom:110px;
right: 10px;
display: flex;
flex-direction: column;
z-index: 18;
}
.userAvatar{
border-radius: 500%;
border-style: solid;
border-width: 2px;
border-color: #ffffff;
}
.userAvatar{
width : 100rpx;
height: 100rpx;
}
.likeIco,.shareIco,.commentIco{
width : 60rpx;
height: 60rpx;
margin-top: 15px;
}
.likeNum,.commentNum,.shareTex{
color: #ffffff;
font-size: 30rpx;
text-align: center;
margin: 5px;
}
.likeNumActive{
color: red;
}
.content{
width: 620rpx;
z-index: 99;
position: absolute;
bottom: 50px;
/* justify-content: center; */
padding: 15rpx;
flex-direction: column;
justify-content: flex-start;
color: #ffffff;
z-index: 12;
/* background-color: aqua; */
}
.userName {
font-size: 30rpx;
color: #ffffff;
margin-top: 80upx;
}
.words {
margin-top: 10rpx;
font-size: 30rpx;
color: #ffffff;
}
.root{
background-color: #000000;
}
</style>

View File

@ -51,12 +51,12 @@
</view> </view>
<view class="userInfo"> <view class="userInfo">
<!-- 1.头像 --> <!-- 1.头像 -->
<image @click="tozuozhe" class="userAvatar" :src="list.artificerImg" mode="aspectFill"></image> <image @click="tozuozhe(list)" class="userAvatar" :src="list.artificerImg" mode="aspectFill"></image>
<!-- 2.点赞 --> <!-- 2.点赞 -->
<view class="list-view" @click="cLike(list.like);" style="opacity: 0.9; margin-top: 17px;"> <view class="list-view" @click="cLike(list.sfdz);" style="opacity: 0.9; margin-top: 17px;">
<image v-if="list.like" src="@/static/img/index/xin.png" style="width: 40px; height: 40px; position: absolute; right: 6px;"></image> <image v-if="list.sfdz=='1'" src="@/static/img/index/xin.png" style="width: 40px; height: 40px; position: absolute; right: 6px;"></image>
<image v-if="!list.like" src="@/static/img/index/xin-2.png" style="width: 40px; height: 40px; position: absolute; right: 6px;"></image> <image v-if="list.sfdz=='0'" src="@/static/img/index/xin-2.png" style="width: 40px; height: 40px; position: absolute; right: 6px;"></image>
<text style="color: #FFFFFF; margin-top: 5px; font-size: 14px; text-align: center; margin-top: 40px; font-weight: bold;" :class="{'likeNumActive':list.like}">{{list.dzs}}</text> <text style="color: #FFFFFF; margin-top: 5px; font-size: 14px; text-align: center; margin-top: 40px; font-weight: bold;" :class="{'likeNumActive':list.sfdz}">{{list.dzs}}</text>
</view> </view>
<!-- 3.评论 --> <!-- 3.评论 -->
<view class="comment list-view" @click="toComment(index)" style="opacity: 0.9; margin-top: 17px;"> <view class="comment list-view" @click="toComment(index)" style="opacity: 0.9; margin-top: 17px;">
@ -68,12 +68,12 @@
<image src="@/static/img/index/share-fill.png" style="width: 40px; height: 40px; position: absolute; right: 5px;"></image> <image src="@/static/img/index/share-fill.png" style="width: 40px; height: 40px; position: absolute; right: 5px;"></image>
<text style="color: #FFFFFF; margin-top: 5px; font-size: 14px; text-align: center; font-weight: bold; margin-top: 40px;">分享</text> <text style="color: #FFFFFF; margin-top: 5px; font-size: 14px; text-align: center; font-weight: bold; margin-top: 40px;">分享</text>
</view> --> </view> -->
<view @click="dealVoice" class="list-view" style="margin-top: 17px;"> <!-- <view @click="dealVoice" class="list-view" style="margin-top: 17px;">
<view style="width: 48px; height: 48px; border-radius: 50px; position: absolute; right: 2.5px;"> <view style="width: 48px; height: 48px; border-radius: 50px; position: absolute; right: 2.5px;">
<image :style="'width: 48px; height: 48px; border-radius: 50px; transform: rotate('+ rotates +'deg);'" src="@/static/img/index/bfq.png" mode="aspectFill"></image> <image :style="'width: 48px; height: 48px; border-radius: 50px; transform: rotate('+ rotates +'deg);'" src="@/static/img/index/bfq.png" mode="aspectFill"></image>
<image v-if="showPlay" :style="'width: 30px; height: 30px; margin-top: 9px; margin-left: 9px; position: absolute; border-radius: 50px; transform: rotate('+ rotates +'deg);'" :src="list.href" mode="aspectFill"></image> <image v-if="showPlay" :style="'width: 30px; height: 30px; margin-top: 9px; margin-left: 9px; position: absolute; border-radius: 50px; transform: rotate('+ rotates +'deg);'" :src="list.href" mode="aspectFill"></image>
</view> </view>
</view> </view> -->
</view> </view>
<!-- 最底下的文字部分 --> <!-- 最底下的文字部分 -->
<view class="content" style="display: flex;flex-direction: column;"> <view class="content" style="display: flex;flex-direction: column;">
@ -95,9 +95,10 @@
</view> </view>
</swiper-item> </swiper-item>
</swiper> </swiper>
<uni-popup type="bottom" ref="pinglun" @touchmove.stop.prevent="moveHandle"> <uni-popup class="uni-popup" type="bottom" ref="pinglun" @touchmove.stop.prevent="moveHandle">
<view :style="'width: '+ windowWidth +'px; height: '+ (boxStyle.height/heightNum) +'px; background-color: #242424; border-top-left-radius: 10px; border-top-right-radius: 10px;'"> <view class="popup-content" :style="'width: '+ windowWidth +'px; height: '+ (boxStyle.height/heightNum) +'px;'">
<CComment ref="ccRef" :userInfo="userInfo" :tableData="tableData" :tableTotal="tableTotal" likeFun="likeFun" @replyFun="replyFun" @deleteFun="deleteFun" :deleteMode="deleteMode"></CComment>
<div class="btn" @click="openComment">发一条新评论</div>
<!-- <douyin-scrollview <!-- <douyin-scrollview
:Width="windowWidth" :Width="windowWidth"
:Height="(boxStyle.height/1.23)" :Height="(boxStyle.height/1.23)"
@ -115,13 +116,23 @@
let audo = uni.createInnerAudioContext() let audo = uni.createInnerAudioContext()
audo.loop = true audo.loop = true
import douyinScrollview from '@/components/douyin-scrollview/douyin-scrollview.vue' import douyinScrollview from '@/components/douyin-scrollview/douyin-scrollview.vue'
import CComment from "@/components/XJ-comment/index";
export default { export default {
components:{ components:{
douyinScrollview douyinScrollview,
CComment
}, },
data() { data() {
return { return {
ccRef: null,
userInfo: {
id: 120,
user_name: "🍁",
user_avatar: "https://pic1.zhimg.com/80/v2-a79071a705f55c5d88f6c74e6111fe84_720w.webp",
},
tableTotal: 4,
tableData: [],
deleteMode: "all",
windowWidth: 0, windowWidth: 0,
windowHeight: 0, windowHeight: 0,
platform: "", platform: "",
@ -272,6 +283,7 @@
// #ifndef MP // #ifndef MP
this.rotateX(); this.rotateX();
// #endif // #endif
}, },
onShow(){ onShow(){
console.log('回到前台'); console.log('回到前台');
@ -303,7 +315,126 @@
// #endif // #endif
console.log('到后台'); console.log('到后台');
}, },
methods: { methods: {
openComment() {//
this.$refs.ccRef.newCommentFun();
},
likeFun(params, callback) {//
console.log("likeFun", params);
// Implement your logic for likeFun
},
toComment(index){
//
/*
1先加载缓冲
2获取当前视频 ID 信息
3🌟🌟🌟🌟重要🌟🌟🌟🌟
- 一定要记得看 index.vue 里面
uni.setStorageSync("user",this.peopleList[i]);
这个东西用于存储当前用户信息 插件里面会使用到这个东西
记得写一下
4打开评论
*/
uni.showToast({
title: '加载中...',
icon: 'none',
position: 'bottom',
duration: 300
})
uni.setStorageSync("videoID",this.dataList[index].id);
this.videoID = this.dataList[index].id;
this.$refs.pinglun.open('bottom');
this.getPingL(this.videoID);
},
getPingL(shipinquanId){//
var data={
page: this.page,
limit:310,
shipinquanId:shipinquanId
}
this.$Request.get("/app/shipinquan/contentlist", data).then(res => {
if (res.code == 0) {
var msg = res.data.records||{}
this.tableTotal=res.data.total;
var list=[];
// for (let i = 0; i < msg.length; i++) {
// list.push(msg[i])
// }
this.tableData = msg.map(item => {
return {
...item,
parent_id: null,
reply_id: null,
reply_name: null,
user_name: item.name?item.name:'盛安',
user_avatar: item.filePath?item.filePath:'../../static/logo.png',
user_content: item.content,
is_like: true,
like_count: 8,
create_time: item.createTime
};
});
} else {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
});
},
replyFun(params, callback) {
// console.log("replyFun", params);
var data={
createBy:uni.getStorageSync('userId'),
content:params.params.user_content,
shipinquanId:this.videoID,
}
this.$Request.post("/app/shipinquan/addContent",data).then(res => {
if (res.code == 0) {
setTimeout(() => this.getPingL(this.videoID), 500);
uni.hideLoading();
callback(this.videoID);
} else {
uni.hideLoading();
uni.showToast({
title: res.msg,
icon: 'none'
})
}
});
// const res = { id: Math.random() }; // ! id! !
// setTimeout(() => callback(res), 500); // , callback
},
deleteFun({ params, mode }, callback) {
console.log("deleteFun", { params, mode });
// , callback;
switch (this.deleteMode) {
case "bind":
// : update
setTimeout(() => callback(), 500); // , callback
break;
case "only":
// : delete
setTimeout(() => callback(), 500); // , callback
break;
default:
// all
// : [delete]
// Demo:
// axios.post("http://xxx/delete", { ids: params }).then((res) => {
// if (res.code === 0) {
// callback(res);
// }
// });
setTimeout(() => callback(), 500); // , callback
break;
}
},
closeScrollview(){ closeScrollview(){
// //
this.$refs.pinglun.close('bottom'); this.$refs.pinglun.close('bottom');
@ -340,7 +471,11 @@
this.onTabItemTaps(); this.onTabItemTaps();
} }
}, },
tozuozhe(){ tozuozhe(item){
// console.log("itemitemitemitemitem",item)
uni.reLaunch({
url:'/pages/therapist/orderDetail?artificerId='+item.createBy+'&classifyId='+'undefined'
})
this.currents = 1// this.currents = 1//
}, },
mpTouchend(){ mpTouchend(){
@ -379,7 +514,6 @@
this.rotates += 1; this.rotates += 1;
},30) },30)
}, },
ended(){ ended(){
// 1. // 1.
// this.current = this.k+1 // this.current = this.k+1
@ -437,9 +571,24 @@
}, },
// ---- --- ending // ---- --- ending
doubleLike(){ doubleLike(){
if(this.dataList[this.k].like == false){ if(this.dataList[this.k].sfdz == '0'){
this.dataList[this.k].dzs += 1;
this.dataList[this.k].like = true; var data={
createBy:uni.getStorageSync('userId'),
shipinquanId:this.dataList[this.k].id,
}
this.$Request.post("/app/shipinquan/addDianzan", data).then(res => {
if (res.code == 0) {
this.dataList[this.k].dzs += 1;
this.dataList[this.k].sfdz = '1';
} else {
this.dataList[this.k].sfdz ='0'
uni.showToast({
title: res.msg,
icon: 'none'
})
}
});
} }
/* /*
点赞 点赞
@ -644,42 +793,20 @@
icon: 'none' icon: 'none'
}) })
}, },
toComment(index){
//
/*
1先加载缓冲
2获取当前视频 ID 信息
3🌟🌟🌟🌟重要🌟🌟🌟🌟
- 一定要记得看 index.vue 里面
uni.setStorageSync("user",this.peopleList[i]);
这个东西用于存储当前用户信息 插件里面会使用到这个东西
记得写一下
4打开评论
*/
uni.showToast({
title: '加载中...',
icon: 'none',
position: 'bottom',
duration: 300
})
uni.setStorageSync("videoID",this.dataList[index].id);
this.videoID = this.dataList[index].id;
this.$refs.pinglun.open('bottom')
},
cLike(sss){ cLike(sss){
var data={ var data={
createBy:this.dataList[this.k].createBy, createBy:uni.getStorageSync('userId'),
shipinquanId:this.dataList[this.k].id, shipinquanId:this.dataList[this.k].id,
} }
this.dataList[this.k].like = !this.dataList[this.k].like this.dataList[this.k].sfdz = !this.dataList[this.k].sfdz
if(this.dataList[this.k].like==true){ if(this.dataList[this.k].sfdz=='1'){
this.$Request.post("/app/shipinquan/addDianzan", data).then(res => { this.$Request.post("/app/shipinquan/addDianzan", data).then(res => {
if (res.code == 0) { if (res.code == 0) {
const video = this.dataList[this.k]; const video = this.dataList[this.k];
sss=video.dzs += 1; sss=video.dzs += 1;
} else { } else {
this.dataList[this.k].like =false this.dataList[this.k].sfdz ='0'
uni.showToast({ uni.showToast({
title: res.msg, title: res.msg,
icon: 'none' icon: 'none'
@ -688,12 +815,13 @@
}); });
}else{// }else{//
this.dataList[this.k].sfdz ='0'
this.$Request.post("/app/shipinquan/delDianzan", data).then(res => { this.$Request.post("/app/shipinquan/delDianzan", data).then(res => {
if (res.code == 0) { if (res.code == 0) {
const video = this.dataList[this.k]; const video = this.dataList[this.k];
sss=video.dzs -= 1; sss=video.dzs -= 1;
} else { } else {
this.dataList[this.k].like =true this.dataList[this.k].sfdz ='0'
uni.showToast({ uni.showToast({
title: res.msg, title: res.msg,
icon: 'none' icon: 'none'
@ -709,6 +837,37 @@
</script> </script>
<style scoped> <style scoped>
.uni-popup{
width: 100%;
height: 500px;
overflow: auto;
}
.popup-content{
width: 100%;
height: 100%;
background-color: #242424;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
position: relative;
display: flex;
flex-direction: column;
}
/deep/uni-tabbar /deep/.uni-tabbar-bottom /deep/.uni-tabbar{
z-index: 998;
}
.btn {
text-align: center;
color: #fff;
padding: 20rpx;
margin: 20rpx;
border-radius: 20rpx;
background-color: #2979ff;
position: fixed;
bottom: 0px;
z-index: 666;
width: 90%;
}
.list-view{ .list-view{
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -0,0 +1,115 @@
## 1.1.192024-07-18
- 修复 初始值传入 null 导致input报错的bug
## 1.1.182024-04-11
- 修复 easyinput组件双向绑定问题
## 1.1.172024-03-28
- 修复 在头条小程序下丢失事件绑定的问题
## 1.1.162024-03-20
- 修复 在密码输入情况下 清除和小眼睛覆盖bug 在edge浏览器下显示双眼睛bug
## 1.1.152024-02-21
- 新增 左侧插槽left
## 1.1.142024-02-19
- 修复 onBlur的emit传值错误
## 1.1.122024-01-29
- 补充 adjust-position文档属性补充
## 1.1.112024-01-29
- 补充 adjust-position属性传递值Boolean当键盘弹起时是否自动上推页面
## 1.1.102024-01-22
- 去除 移除无用的log输出
## 1.1.92023-04-11
- 修复 vue3 下 keyboardheightchange 事件报错的bug
## 1.1.82023-03-29
- 优化 trim 属性默认值
## 1.1.72023-03-29
- 新增 cursor-spacing 属性
## 1.1.62023-01-28
- 新增 keyboardheightchange 事件,可监听键盘高度变化
## 1.1.52022-11-29
- 优化 主题样式
## 1.1.42022-10-27
- 修复 props 中背景颜色无默认值的bug
## 1.1.02022-06-30
- 新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容
- 新增 clear 事件,点击右侧叉号图标触发
- 新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发
- 优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等
## 1.0.52022-06-07
- 优化 clearable 显示策略
## 1.0.42022-06-07
- 优化 clearable 显示策略
## 1.0.32022-05-20
- 修复 关闭图标某些情况下无法取消的 bug
## 1.0.22022-04-12
- 修复 默认值不生效的 bug
## 1.0.12022-04-02
- 修复 value 不能为 0 的 bug
## 1.0.02021-11-19
- 优化 组件 UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-easyinput](https://uniapp.dcloud.io/component/uniui/uni-easyinput)
## 0.1.42021-08-20
- 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug
## 0.1.32021-08-11
- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
## 0.1.22021-07-30
- 优化 vue3 下事件警告的问题
## 0.1.1
- 优化 errorMessage 属性支持 Boolean 类型
## 0.1.02021-07-13
- 组件兼容 vue3如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.0.162021-06-29
- 修复 confirmType 属性(仅 type="text" 生效)导致多行文本框无法换行的 bug
## 0.0.152021-06-21
- 修复 passwordIcon 属性拼写错误的 bug
## 0.0.142021-06-18
- 新增 passwordIcon 属性,当 type=password 时是否显示小眼睛图标
- 修复 confirmType 属性不生效的问题
## 0.0.132021-06-04
- 修复 disabled 状态可清出内容的 bug
## 0.0.122021-05-12
- 新增 组件示例地址
## 0.0.112021-05-07
- 修复 input-border 属性不生效的问题
## 0.0.102021-04-30
- 修复 ios 遮挡文字、显示一半的问题
## 0.0.92021-02-05
- 调整为 uni_modules 目录规范
- 优化 兼容 nvue 页面

View File

@ -0,0 +1,54 @@
/**
* @desc 函数防抖
* @param func 目标函数
* @param wait 延迟执行毫秒数
* @param immediate true - 立即执行 false - 延迟执行
*/
export const debounce = function(func, wait = 1000, immediate = true) {
let timer;
return function() {
let context = this,
args = arguments;
if (timer) clearTimeout(timer);
if (immediate) {
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait);
if (callNow) func.apply(context, args);
} else {
timer = setTimeout(() => {
func.apply(context, args);
}, wait)
}
}
}
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 使用表时间戳在时间段开始的时候触发 2 使用表定时器在时间段结束的时候触发
*/
export const throttle = (func, wait = 1000, type = 1) => {
let previous = 0;
let timeout;
return function() {
let context = this;
let args = arguments;
if (type === 1) {
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
} else if (type === 2) {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
}

View File

@ -0,0 +1,676 @@
<template>
<view class="uni-easyinput" :class="{ 'uni-easyinput-error': msg }" :style="boxStyle">
<view class="uni-easyinput__content" :class="inputContentClass" :style="inputContentStyle">
<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc" @click="onClickIcon('prefix')" size="22"></uni-icons>
<slot name="left">
</slot>
<!-- #ifdef MP-ALIPAY -->
<textarea :enableNative="enableNative" v-if="type === 'textarea'" class="uni-easyinput__content-textarea" :class="{ 'input-padding': inputBorder }" :name="name" :value="val" :placeholder="placeholder" :placeholderStyle="placeholderStyle" :disabled="disabled" placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused" :autoHeight="autoHeight" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange"></textarea>
<input :enableNative="enableNative" v-else :type="type === 'password' ? 'text' : type" class="uni-easyinput__content-input" :style="inputStyle" :name="name" :value="val" :password="!showPassword && type === 'password'" :placeholder="placeholder" :placeholderStyle="placeholderStyle" placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength" :focus="focused" :confirmType="confirmType" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @focus="_Focus" @blur="_Blur" @input="onInput" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange" />
<!-- #endif -->
<!-- #ifndef MP-ALIPAY -->
<textarea v-if="type === 'textarea'" class="uni-easyinput__content-textarea" :class="{ 'input-padding': inputBorder }" :name="name" :value="val" :placeholder="placeholder" :placeholderStyle="placeholderStyle" :disabled="disabled" placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused" :autoHeight="autoHeight" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange"></textarea>
<input v-else :type="type === 'password' ? 'text' : type" class="uni-easyinput__content-input" :style="inputStyle" :name="name" :value="val" :password="!showPassword && type === 'password'" :placeholder="placeholder" :placeholderStyle="placeholderStyle" placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength" :focus="focused" :confirmType="confirmType" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @focus="_Focus" @blur="_Blur" @input="onInput" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange" />
<!-- #endif -->
<template v-if="type === 'password' && passwordIcon">
<!-- 开启密码时显示小眼睛 -->
<uni-icons v-if="isVal" class="content-clear-icon" :class="{ 'is-textarea-icon': type === 'textarea' }" :type="showPassword ? 'eye-slash-filled' : 'eye-filled'" :size="22" :color="focusShow ? primaryColor : '#c0c4cc'" @click="onEyes"></uni-icons>
</template>
<template v-if="suffixIcon">
<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc" @click="onClickIcon('suffix')" size="22"></uni-icons>
</template>
<template v-else>
<uni-icons v-if="clearable && isVal && !disabled && type !== 'textarea'" class="content-clear-icon" :class="{ 'is-textarea-icon': type === 'textarea' }" type="clear" :size="clearSize" :color="msg ? '#dd524d' : focusShow ? primaryColor : '#c0c4cc'" @click="onClear"></uni-icons>
</template>
<slot name="right"></slot>
</view>
</view>
</template>
<script>
/**
* Easyinput 输入框
* @description 此组件可以实现表单的输入与校验包括 "text" "textarea" 类型
* @tutorial https://ext.dcloud.net.cn/plugin?id=3455
* @property {String} value 输入内容
* @property {String } type 输入框的类型默认text password/text/textarea/..
* @value text 文本输入键盘
* @value textarea 多行文本输入键盘
* @value password 密码输入键盘
* @value number 数字输入键盘注意iOS上app-vue弹出的数字键盘并非9宫格方式
* @value idcard 身份证输入键盘支付宝百度QQ小程序
* @value digit 带小数点的数字键盘 App的nvue页面微信支付宝百度头条QQ小程序支持
* @property {Boolean} clearable 是否显示右侧清空内容的图标控件点击可清空输入框内容默认true
* @property {Boolean} autoHeight 是否自动增高输入区域type为textarea时有效默认true
* @property {String } placeholder 输入框的提示文字
* @property {String } placeholderStyle placeholder的样式(内联样式字符串)"color: #ddd"
* @property {Boolean} focus 是否自动获得焦点默认false
* @property {Boolean} disabled 是否禁用默认false
* @property {Number } maxlength 最大输入长度设置为 -1 的时候不限制最大长度默认140
* @property {String } confirmType 设置键盘右下角按钮的文字仅在type="text"时生效默认done
* @property {Number } clearSize 清除图标的大小单位px默认15
* @property {String} prefixIcon 输入框头部图标
* @property {String} suffixIcon 输入框尾部图标
* @property {String} primaryColor 设置主题色默认#2979ff
* @property {Boolean} trim 是否自动去除两端的空格
* @property {Boolean} cursorSpacing 指定光标与键盘的距离单位 px
* @property {Boolean} ajust-position 当键盘弹起时是否上推内容默认值true
* @value both 去除两端空格
* @value left 去除左侧空格
* @value right 去除右侧空格
* @value start 去除左侧空格
* @value end 去除右侧空格
* @value all 去除全部空格
* @value none 不去除空格
* @property {Boolean} inputBorder 是否显示input输入框的边框默认true
* @property {Boolean} passwordIcon type=password时是否显示小眼睛图标
* @property {Object} styles 自定义颜色
* @event {Function} input 输入框内容发生变化时触发
* @event {Function} focus 输入框获得焦点时触发
* @event {Function} blur 输入框失去焦点时触发
* @event {Function} confirm 点击完成按钮时触发
* @event {Function} iconClick 点击图标时触发
* @example <uni-easyinput v-model="mobile"></uni-easyinput>
*/
function obj2strClass(obj) {
let classess = '';
for (let key in obj) {
const val = obj[key];
if (val) {
classess += `${key} `;
}
}
return classess;
}
function obj2strStyle(obj) {
let style = '';
for (let key in obj) {
const val = obj[key];
style += `${key}:${val};`;
}
return style;
}
export default {
name: 'uni-easyinput',
emits: [
'click',
'iconClick',
'update:modelValue',
'input',
'focus',
'blur',
'confirm',
'clear',
'eyes',
'change',
'keyboardheightchange'
],
model: {
prop: 'modelValue',
event: 'update:modelValue'
},
options: {
// #ifdef MP-TOUTIAO
virtualHost: false,
// #endif
// #ifndef MP-TOUTIAO
virtualHost: true
// #endif
},
inject: {
form: {
from: 'uniForm',
default: null
},
formItem: {
from: 'uniFormItem',
default: null
}
},
props: {
name: String,
value: [Number, String],
modelValue: [Number, String],
type: {
type: String,
default: 'text'
},
clearable: {
type: Boolean,
default: true
},
autoHeight: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: ' '
},
placeholderStyle: String,
focus: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
maxlength: {
type: [Number, String],
default: 140
},
confirmType: {
type: String,
default: 'done'
},
clearSize: {
type: [Number, String],
default: 24
},
inputBorder: {
type: Boolean,
default: true
},
prefixIcon: {
type: String,
default: ''
},
suffixIcon: {
type: String,
default: ''
},
trim: {
type: [Boolean, String],
default: false
},
cursorSpacing: {
type: Number,
default: 0
},
passwordIcon: {
type: Boolean,
default: true
},
adjustPosition: {
type: Boolean,
default: true
},
primaryColor: {
type: String,
default: '#2979ff'
},
styles: {
type: Object,
default () {
return {
color: '#333',
backgroundColor: '#fff',
disableColor: '#F7F6F6',
borderColor: '#e5e5e5'
};
}
},
errorMessage: {
type: [String, Boolean],
default: ''
},
// #ifdef MP-ALIPAY
enableNative: {
type: Boolean,
default: false
}
// #endif
},
data() {
return {
focused: false,
val: '',
showMsg: '',
border: false,
isFirstBorder: false,
showClearIcon: false,
showPassword: false,
focusShow: false,
localMsg: '',
isEnter: false // 使
};
},
computed: {
//
isVal() {
const val = this.val;
// fixed by mehaotian 00
if (val || val === 0) {
return true;
}
return false;
},
msg() {
// console.log('computed', this.form, this.formItem);
// if (this.form) {
// return this.errorMessage || this.formItem.errMsg;
// }
// TODO formItem errMsg
return this.localMsg || this.errorMessage;
},
// uniappinputmaxlength
inputMaxlength() {
return Number(this.maxlength);
},
// style
boxStyle() {
return `color:${
this.inputBorder && this.msg ? '#e43d33' : this.styles.color
};`;
},
// input
inputContentClass() {
return obj2strClass({
'is-input-border': this.inputBorder,
'is-input-error-border': this.inputBorder && this.msg,
'is-textarea': this.type === 'textarea',
'is-disabled': this.disabled,
'is-focused': this.focusShow
});
},
inputContentStyle() {
const focusColor = this.focusShow ?
this.primaryColor :
this.styles.borderColor;
const borderColor =
this.inputBorder && this.msg ? '#dd524d' : focusColor;
return obj2strStyle({
'border-color': borderColor || '#e5e5e5',
'background-color': this.disabled ?
this.styles.disableColor : this.styles.backgroundColor
});
},
// input
inputStyle() {
const paddingRight =
this.type === 'password' || this.clearable || this.prefixIcon ?
'' :
'10px';
return obj2strStyle({
'padding-right': paddingRight,
'padding-left': this.prefixIcon ? '' : '10px'
});
}
},
watch: {
value(newVal) {
// fix by mehaotian nullinputbug
if (newVal === null) {
this.val = '';
return
}
this.val = newVal;
},
modelValue(newVal) {
if (newVal === null) {
this.val = '';
return
}
this.val = newVal;
},
focus(newVal) {
this.$nextTick(() => {
this.focused = this.focus;
this.focusShow = this.focus;
});
}
},
created() {
this.init();
// TODO vue3 computed inject formItem.errMsg
if (this.form && this.formItem) {
this.$watch('formItem.errMsg', newVal => {
this.localMsg = newVal;
});
}
},
mounted() {
this.$nextTick(() => {
this.focused = this.focus;
this.focusShow = this.focus;
});
},
methods: {
/**
* 初始化变量值
*/
init() {
if (this.value || this.value === 0) {
this.val = this.value;
} else if (
this.modelValue ||
this.modelValue === 0 ||
this.modelValue === ''
) {
this.val = this.modelValue;
} else {
// fix by ht nullinput
this.val = '';
}
},
/**
* 点击图标时触发
* @param {Object} type
*/
onClickIcon(type) {
this.$emit('iconClick', type);
},
/**
* 显示隐藏内容密码框时生效
*/
onEyes() {
this.showPassword = !this.showPassword;
this.$emit('eyes', this.showPassword);
},
/**
* 输入时触发
* @param {Object} event
*/
onInput(event) {
let value = event.detail.value;
//
if (this.trim) {
if (typeof this.trim === 'boolean' && this.trim) {
value = this.trimStr(value);
}
if (typeof this.trim === 'string') {
value = this.trimStr(value, this.trim);
}
}
if (this.errMsg) this.errMsg = '';
this.val = value;
// TODO vue2
this.$emit('input', value);
// TODO  vue3
this.$emit('update:modelValue', value);
},
/**
* 外部调用方法
* 获取焦点时触发
* @param {Object} event
*/
onFocus() {
this.$nextTick(() => {
this.focused = true;
});
this.$emit('focus', null);
},
_Focus(event) {
this.focusShow = true;
this.$emit('focus', event);
},
/**
* 外部调用方法
* 失去焦点时触发
* @param {Object} event
*/
onBlur() {
this.focused = false;
this.$emit('blur', null);
},
_Blur(event) {
let value = event.detail.value;
this.focusShow = false;
this.$emit('blur', event);
// eventstring
if (this.isEnter === false) {
this.$emit('change', this.val);
}
//
if (this.form && this.formItem) {
const { validateTrigger } = this.form;
if (validateTrigger === 'blur') {
this.formItem.onFieldChange();
}
}
},
/**
* 按下键盘的发送键
* @param {Object} e
*/
onConfirm(e) {
this.$emit('confirm', this.val);
this.isEnter = true;
this.$emit('change', this.val);
this.$nextTick(() => {
this.isEnter = false;
});
},
/**
* 清理内容
* @param {Object} event
*/
onClear(event) {
this.val = '';
// TODO vue2
this.$emit('input', '');
// TODO vue2
// TODO  vue3
this.$emit('update:modelValue', '');
//
this.$emit('clear');
},
/**
* 键盘高度发生变化的时候触发此事件
* 兼容性微信小程序2.7.0+App 3.1.0+
* @param {Object} event
*/
onkeyboardheightchange(event) {
this.$emit('keyboardheightchange', event);
},
/**
* 去除空格
*/
trimStr(str, pos = 'both') {
if (pos === 'both') {
return str.trim();
} else if (pos === 'left') {
return str.trimLeft();
} else if (pos === 'right') {
return str.trimRight();
} else if (pos === 'start') {
return str.trimStart();
} else if (pos === 'end') {
return str.trimEnd();
} else if (pos === 'all') {
return str.replace(/\s+/g, '');
} else if (pos === 'none') {
return str;
}
return str;
}
}
};
</script>
<style lang="scss">
$uni-error: #e43d33;
$uni-border-1: #dcdfe6 !default;
.uni-easyinput {
/* #ifndef APP-NVUE */
width: 100%;
/* #endif */
flex: 1;
position: relative;
text-align: left;
color: #333;
font-size: 14px;
}
.uni-easyinput__content {
flex: 1;
/* #ifndef APP-NVUE */
width: 100%;
display: flex;
box-sizing: border-box;
// min-height: 36px;
/* #endif */
flex-direction: row;
align-items: center;
// border
border-color: #fff;
transition-property: border-color;
transition-duration: 0.3s;
}
.uni-easyinput__content-input {
/* #ifndef APP-NVUE */
width: auto;
/* #endif */
position: relative;
overflow: hidden;
flex: 1;
line-height: 1;
font-size: 14px;
height: 35px;
// min-height: 36px;
/*ifdef H5*/
& ::-ms-reveal {
display: none;
}
& ::-ms-clear {
display: none;
}
& ::-o-clear {
display: none;
}
/*endif*/
}
.uni-easyinput__placeholder-class {
color: #999;
font-size: 12px;
// font-weight: 200;
}
.is-textarea {
align-items: flex-start;
}
.is-textarea-icon {
margin-top: 5px;
}
.uni-easyinput__content-textarea {
position: relative;
overflow: hidden;
flex: 1;
line-height: 1.5;
font-size: 14px;
margin: 6px;
margin-left: 0;
height: 80px;
min-height: 80px;
/* #ifndef APP-NVUE */
min-height: 80px;
width: auto;
/* #endif */
}
.input-padding {
padding-left: 10px;
}
.content-clear-icon {
padding: 0 5px;
}
.label-icon {
margin-right: 5px;
margin-top: -1px;
}
//
.is-input-border {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-direction: row;
align-items: center;
border: 1px solid $uni-border-1;
border-radius: 4px;
/* #ifdef MP-ALIPAY */
overflow: hidden;
/* #endif */
}
.uni-error-message {
position: absolute;
bottom: -17px;
left: 0;
line-height: 12px;
color: $uni-error;
font-size: 12px;
text-align: left;
}
.uni-error-msg--boeder {
position: relative;
bottom: 0;
line-height: 22px;
}
.is-input-error-border {
border-color: $uni-error;
.uni-easyinput__placeholder-class {
color: mix(#fff, $uni-error, 50%);
}
}
.uni-easyinput--border {
margin-bottom: 0;
padding: 10px 15px;
// padding-bottom: 0;
border-top: 1px #eee solid;
}
.uni-easyinput-error {
padding-bottom: 0;
}
.is-first-border {
/* #ifndef APP-NVUE */
border: none;
/* #endif */
/* #ifdef APP-NVUE */
border-width: 0;
/* #endif */
}
.is-disabled {
background-color: #f7f6f6;
color: #d5d5d5;
.uni-easyinput__placeholder-class {
color: #d5d5d5;
font-size: 12px;
}
}
</style>

View File

@ -0,0 +1,88 @@
{
"id": "uni-easyinput",
"displayName": "uni-easyinput 增强输入框",
"version": "1.1.19",
"description": "Easyinput 组件是对原生input组件的增强",
"keywords": [
"uni-ui",
"uniui",
"input",
"uni-easyinput",
"输入框"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [
"uni-scss",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y",
"alipay": "n"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,11 @@
### Easyinput 增强输入框
> **组件名uni-easyinput**
> 代码块: `uEasyinput`
easyinput 组件是对原生input组件的增强 ,是专门为配合表单组件[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)而设计的easyinput 内置了边框,图标等,同时包含 input 所有功能
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-easyinput)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -0,0 +1,23 @@
## 2.1.12024-03-20
- 优化 app下边框过窄导致不显示的bug
## 2.1.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-tag](https://uniapp.dcloud.io/component/uniui/uni-tag)
## 2.0.02021-11-09
- 新增 提供组件设计资源,组件样式调整
- 移除 插槽
- 移除 type 属性的 royal 选项
## 1.1.12021-08-11
- type 不是 default 时size 为 small 字体大小显示不正确
## 1.1.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.72021-06-18
- 修复 uni-tag 在字节跳动小程序上 css 类名编译错误的 bug
## 1.0.62021-06-04
- 修复 未定义 sass 变量 "$uni-color-royal" 的bug
## 1.0.52021-05-10
- 修复 royal 类型无效的bug
- 修复 uni-tag 宽度不自适应的bug
- 新增 uni-tag 支持属性 custom-style 自定义样式
## 1.0.42021-02-05
- 调整为uni_modules目录规范

View File

@ -0,0 +1,252 @@
<template>
<text class="uni-tag" v-if="text" :class="classes" :style="customStyle" @click="onClick">{{text}}</text>
</template>
<script>
/**
* Tag 标签
* @description 用于展示1个或多个文字标签可点击切换选中不选中的状态
* @tutorial https://ext.dcloud.net.cn/plugin?id=35
* @property {String} text 标签内容
* @property {String} size = [default|small|mini] 大小尺寸
* @value default 正常
* @value small 小尺寸
* @value mini 迷你尺寸
* @property {String} type = [default|primary|successwarningerror] 颜色类型
* @value default 灰色
* @value primary 蓝色
* @value success 绿色
* @value warning 黄色
* @value error 红色
* @property {Boolean} disabled = [true|false] 是否为禁用状态
* @property {Boolean} inverted = [true|false] 是否无需背景颜色空心标签
* @property {Boolean} circle = [true|false] 是否为圆角
* @event {Function} click 点击 Tag 触发事件
*/
export default {
name: "UniTag",
emits: ['click'],
props: {
type: {
// defaultprimarysuccesswarningerrorroyal
type: String,
default: "default"
},
size: {
// normal, small
type: String,
default: "normal"
},
//
text: {
type: String,
default: ""
},
disabled: {
//
type: [Boolean, String],
default: false
},
inverted: {
//
type: [Boolean, String],
default: false
},
circle: {
//
type: [Boolean, String],
default: false
},
mark: {
//
type: [Boolean, String],
default: false
},
customStyle: {
type: String,
default: ''
}
},
computed: {
classes() {
const {
type,
disabled,
inverted,
circle,
mark,
size,
isTrue
} = this
const classArr = [
'uni-tag--' + type,
'uni-tag--' + size,
isTrue(disabled) ? 'uni-tag--disabled' : '',
isTrue(inverted) ? 'uni-tag--' + type + '--inverted' : '',
isTrue(circle) ? 'uni-tag--circle' : '',
isTrue(mark) ? 'uni-tag--mark' : '',
// type === 'default' ? 'uni-tag--default' : 'uni-tag-text',
isTrue(inverted) ? 'uni-tag--inverted uni-tag-text--' + type : '',
size === 'small' ? 'uni-tag-text--small' : ''
]
//
return classArr.join(' ')
}
},
methods: {
isTrue(value) {
return value === true || value === 'true'
},
onClick() {
if (this.isTrue(this.disabled)) return
this.$emit("click");
}
}
};
</script>
<style lang="scss" scoped>
$uni-primary: #2979ff !default;
$uni-success: #18bc37 !default;
$uni-warning: #f3a73f !default;
$uni-error: #e43d33 !default;
$uni-info: #8f939c !default;
$tag-default-pd: 4px 7px;
$tag-small-pd: 2px 5px;
$tag-mini-pd: 1px 3px;
.uni-tag {
line-height: 14px;
font-size: 12px;
font-weight: 200;
padding: $tag-default-pd;
color: #fff;
border-radius: 3px;
background-color: $uni-info;
border-width: 1px;
border-style: solid;
border-color: $uni-info;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
// size attr
&--default {
font-size: 12px;
}
&--default--inverted {
color: $uni-info;
border-color: $uni-info;
}
&--small {
padding: $tag-small-pd;
font-size: 12px;
border-radius: 2px;
}
&--mini {
padding: $tag-mini-pd;
font-size: 12px;
border-radius: 2px;
}
// type attr
&--primary {
background-color: $uni-primary;
border-color: $uni-primary;
color: #fff;
}
&--success {
color: #fff;
background-color: $uni-success;
border-color: $uni-success;
}
&--warning {
color: #fff;
background-color: $uni-warning;
border-color: $uni-warning;
}
&--error {
color: #fff;
background-color: $uni-error;
border-color: $uni-error;
}
&--primary--inverted {
color: $uni-primary;
border-color: $uni-primary;
}
&--success--inverted {
color: $uni-success;
border-color: $uni-success;
}
&--warning--inverted {
color: $uni-warning;
border-color: $uni-warning;
}
&--error--inverted {
color: $uni-error;
border-color: $uni-error;
}
&--inverted {
background-color: #fff;
}
// other attr
&--circle {
border-radius: 15px;
}
&--mark {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-top-right-radius: 15px;
border-bottom-right-radius: 15px;
}
&--disabled {
opacity: 0.5;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
}
.uni-tag-text {
color: #fff;
font-size: 14px;
&--primary {
color: $uni-primary;
}
&--success {
color: $uni-success;
}
&--warning {
color: $uni-warning;
}
&--error {
color: $uni-error;
}
&--small {
font-size: 12px;
}
}
</style>

View File

@ -0,0 +1,84 @@
{
"id": "uni-tag",
"displayName": "uni-tag 标签",
"version": "2.1.1",
"description": "Tag 组件用于展示1个或多个文字标签可点击切换选中、不选中的状态。",
"keywords": [
"uni-ui",
"uniui",
"",
"tag",
"标签"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,13 @@
## Tag 标签
> **组件名uni-tag**
> 代码块: `uTag`
用于展示1个或多个文字标签可点击切换选中、不选中的状态 。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-tag)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839