1
0
mirror of https://github.com/ialley-workshop-open/uni-halo.git synced 2026-06-13 21:59:32 +08:00

release: 发布 uni-halo beta-v2.0 版本

This commit is contained in:
小莫唐尼
2024-05-20 01:27:15 +08:00
parent a81c506a14
commit 057a7cf6f0
49 changed files with 2696 additions and 2531 deletions
+6 -6
View File
@@ -1,24 +1,24 @@
<template>
<view class="article-card " :class="cardType" @click="fnClickEvent('card')">
<view class="left">
<cache-image class="thumbnail" radius="6rpx" :url="$utils.checkThumbnailUrl(article.thumbnail)" :fileMd5="$utils.checkThumbnailUrl(article.thumbnail)" mode="aspectFill"></cache-image>
<cache-image class="thumbnail" radius="6rpx" :url="$utils.checkThumbnailUrl(article.spec.cover)" :fileMd5="$utils.checkThumbnailUrl(article.spec.cover)" mode="aspectFill"></cache-image>
<!-- <image class="thumbnail" lazy-load :src="$utils.checkThumbnailUrl(article.thumbnail)" mode="aspectFill"></image> -->
</view>
<view class="right">
<view class="title">
<text class="is-top bg-gradient-blue-accent" v-if="article.topped">置顶</text>
<text class="title-text text-overflow">{{ article.title }}</text>
<text class="is-top bg-gradient-blue-accent" v-if="article.spec.pinned">置顶</text>
<text class="title-text text-overflow">{{ article.spec.title }}</text>
</view>
<view class="content text-overflow-2">{{ article.summary }}</view>
<view class="content text-overflow-2">{{ article.status.excerpt }}</view>
<view class="foot">
<view class="create-time">
<text class="time-label">发布时间</text>
{{ { d: article.createTime, f: 'yyyy-MM-dd' } | formatTime }}
{{ { d: article.spec.publishTime, f: 'yyyy-MM-dd' } | formatTime }}
</view>
<view class="visits">
<!-- <tm-icons :size="24" name="icon-filter-fill"></tm-icons> -->
浏览
<text class="number">{{ article.visits }}</text>
<text class="number">{{ article.stats.visit }}</text>
</view>
</view>
@@ -1,67 +1,79 @@
<template>
<view class="category-mini-card">
<cache-image
class="img"
height="120rpx"
:url="$utils.checkThumbnailUrl(category.thumbnail)"
:fileMd5="$utils.checkThumbnailUrl(category.thumbnail)"
mode="aspectFill"
></cache-image>
<text class="label">{{ category.postCount }}&nbsp;</text>
<view class="name">{{ category.name }}</view>
<cache-image class="img" height="180rpx" :url="$utils.checkThumbnailUrl(category.spec.cover,true)"
:fileMd5="$utils.checkThumbnailUrl(category.spec.cover)" mode="aspectFill"></cache-image>
<view class="content">
<view class="name">{{ category.spec.displayName }}</view>
<text class="label"> {{ category.postCount }} </text>
</view>
</view>
</template>
<script>
export default {
name: 'category-mini-card',
props: {
category: {
type: Object,
default: () => {}
export default {
name: 'category-mini-card',
props: {
category: {
type: Object,
default: () => {}
}
}
}
};
};
</script>
<style scoped lang="scss">
.category-mini-card {
display: inline-block;
width: 260rpx;
height: 180rpx;
position: relative;
border-radius: 12rpx;
background-color: #fff;
overflow: hidden;
box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.03);
position: relative;
.img {
width: 100%;
height: 120rpx;
border: 6rpx 6rpx 0 0;
.category-mini-card {
display: inline-block;
width: 260rpx;
height: 180rpx;
position: relative;
border-radius: 12rpx;
background-color: #fff;
overflow: hidden;
}
.label {
position: absolute;
left: 0;
top: 86rpx;
color: #03a9f4;
font-size: 24rpx;
background-color: rgba(255, 255, 255, 1);
border-radius: 0rpx 24rpx 0 0;
display: flex;
padding: 2rpx 12rpx;
padding-right: 24rpx;
}
.name {
position: absolute;
bottom: 16rpx;
left: 0;
right: 0;
font-size: 24rpx;
box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.03);
position: relative;
text-align: center;
color: #333;
color: #ffffff;
&:before {
content: '';
position: absolute;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(3rpx);
}
.content {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 3;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.img {
width: 100%;
height: 100%;
}
.name {
font-weight: bold;
font-size: 30rpx;
}
.label {
font-size: 24rpx;
margin-top: 6rpx;
}
}
}
</style>
</style>
+121 -132
View File
@@ -1,167 +1,156 @@
<template>
<view class=" comment-item flex flex-col mt-30 pt-24" :class="{ 'child-comment-item': isChild, 'no-solid': !useSolid, classItem }">
<view v-if="comment" class=" comment-item flex flex-col mt-30 pt-24"
:class="{ 'child-comment-item': isChild, 'no-solid': !useSolid, classItem }">
<view class="comment-item_user flex">
<image
v-if="comment.isAdmin"
class="user-avatar"
:class="{ 'is-radius': globalAppSettings.isAvatarRadius }"
:src="bloggerInfo.avatar"
mode="aspectFill"
@error="fnOnImageError(comment)"
></image>
<image
v-else
class="user-avatar"
:class="{ 'is-radius': globalAppSettings.isAvatarRadius }"
:src="comment.avatar"
mode="aspectFill"
@error="fnOnImageError(comment)"
></image>
<image class="user-avatar" :class="{ 'is-radius': globalAppSettings.isAvatarRadius }"
:src="$utils.checkAvatarUrl(comment.owner.avatar, false)" mode="aspectFill" @error="fnOnImageError(comment)"></image>
<view class="user-info pl-14">
<view class="author">
<text class="mr-6 text-grey-darken-1 text-size-m">{{ comment.author }}</text>
<tm-tags v-if="comment.isAdmin" :dense="true" color="bg-gradient-amber-accent" size="xs" model="fill">博主</tm-tags>
<tm-tags v-else :dense="true" color="bg-gradient-light-blue-lighten " size="xs" model="fill">游客</tm-tags>
<text class="mr-6 text-grey-darken-1 text-size-m">{{ comment.owner.displayName }}</text>
</view>
<view class="flex mt-4">
<view v-if="false" class="text-size-s text-grey mr-12">IP属地暂无信息</view>
<view class="time text-size-xs text-grey">
<text class="">{{ $tm.dayjs(comment.createTime).format('YYYY年MM月DD日') }}</text>
<text class="ml-12">{{ $tm.dayjs(comment.createTime).fromNow(true) }}</text>
<text class="">{{ $tm.dayjs(comment.spec.creationTime).format('YYYY年MM月DD日') }}</text>
<text class="ml-12">{{ $tm.dayjs(comment.spec.creationTime).fromNow(true) }}</text>
</view>
</view>
</view>
<view v-if="useActions" class="">
<tm-button v-if="!disallowComment" size="s" text theme="blue" @click="$emit('on-comment', { type: 'user', comment: comment })">回复</tm-button>
<tm-button size="s" text theme="grey" @click="$emit('on-copy', comment.content)"></tm-button>
<tm-button v-if="!disallowComment" size="s" text theme="blue"
@click="$emit('on-comment', { type: 'user', comment: comment })"></tm-button>
<tm-button size="s" text theme="grey" @click="$emit('on-copy', comment.spec.raw)">复制</tm-button>
</view>
</view>
<view class="comment-item_content mt-12" :class="{ 'has-bg': useContentBg, 'not-ml': isChild }" @click="$emit('on-detail', comment)" v-html="comment.content"></view>
<!-- <view v-if="useActions" class="comment-item_info text-size-s text-grey">
<text v-if="false" @click="$emit('on-todo')">点赞</text>
<text @click="$emit('on-comment', { type: 'user', comment: comment })">回复</text>
<text v-if="false" class="ml-24" @click="$emit('on-todo')">举报</text>
<text class="ml-24" @click="$emit('on-copy', comment.content)">复制内容</text>
</view> -->
<view class="comment-item_content mt-12" :class="{ 'has-bg': useContentBg, 'not-ml': isChild }"
@click="$emit('on-detail', comment)" v-html="comment.spec.raw"></view>
</view>
</template>
<script>
import tmTags from '@/tm-vuetify/components/tm-tags/tm-tags.vue';
import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
export default {
name: 'comment-item',
components: { tmTags, tmButton },
props: {
classItem: {
type: Array,
default: () => []
import tmTags from '@/tm-vuetify/components/tm-tags/tm-tags.vue';
import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
export default {
name: 'comment-item',
components: {
tmTags,
tmButton
},
disallowComment: {
type: Boolean,
default: false
props: {
classItem: {
type: Array,
default: () => []
},
disallowComment: {
type: Boolean,
default: false
},
useActions: {
type: Boolean,
default: true
},
useSolid: {
type: Boolean,
default: true
},
useContentBg: {
type: Boolean,
default: true
},
isChild: {
type: Boolean,
default: false
},
postName: {
type: String,
default: ""
},
comment: {
type: Object,
default: () => null
}
},
useActions: {
type: Boolean,
default: true
computed: {
// 获取博主信息
bloggerInfo() {
let blogger = this.$tm.vx.getters().getBlogger;
blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true);
return blogger;
}
},
useSolid: {
type: Boolean,
default: true
},
useContentBg: {
type: Boolean,
default: true
},
isChild: {
type: Boolean,
default: false
},
postId: {
type: Number,
default: null
},
comment: {
type: Object,
default: () => {}
}
},
computed: {
// 获取博主信息
bloggerInfo() {
let blogger = this.$tm.vx.getters().getBlogger;
blogger.avatar = this.$utils.checkAvatarUrl(blogger.avatar, true);
return blogger;
}
},
methods: {
fnOnImageError(data) {
if (data.isAdmin) {
data.avatar = this.$haloConfig.author.avatar;
} else {
methods: {
fnOnImageError(data) {
data.avatar = `${this.$haloConfig.defaultAvatarUrl}&rt=${new Date().getTime()}`;
}
},
created() {
console.log("comment",this.comment)
}
}
};
};
</script>
<style scoped lang="scss">
.comment-item {
box-sizing: border-box;
border-top: 2rpx solid #f5f5f5;
.comment-item {
box-sizing: border-box;
border-top: 2rpx solid #f5f5f5;
&.child-comment-item {
padding-top: 0;
margin-left: 80rpx;
border: 0;
}
&.no-solid {
border: 0;
margin-top: 0 !important;
}
&_user {
display: flex;
align-items: center;
.user-avatar {
width: 70rpx;
height: 70rpx;
box-sizing: border-box;
box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.05);
border: 4rpx solid #ffffff;
border-radius: 12rpx;
&.is-radius {
border-radius: 50%;
&.child-comment-item {
padding-top: 0;
margin-left: 80rpx;
border: 0;
}
&.no-solid {
border: 0;
margin-top: 0 !important;
}
&_user {
display: flex;
align-items: center;
.user-avatar {
width: 70rpx;
height: 70rpx;
box-sizing: border-box;
box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.05);
border: 4rpx solid #ffffff;
border-radius: 12rpx;
&.is-radius {
border-radius: 50%;
}
}
.user-info {
width: 0;
flex-grow: 1;
}
}
.user-info {
width: 0;
flex-grow: 1;
}
}
&_content {
font-size: 28rpx;
margin-left: 80rpx;
box-sizing: border-box;
border-radius: 10rpx;
line-height: 1.8;
color: var(--main-text-color);
&.has-bg {
background-color: #fafafa;
padding: 6rpx 24rpx;
&_content {
font-size: 28rpx;
margin-left: 80rpx;
box-sizing: border-box;
border-radius: 10rpx;
line-height: 1.8;
color: var(--main-text-color);
&.has-bg {
background-color: #fafafa;
padding: 6rpx 24rpx;
}
&.not-ml {
margin-left: 80rpx;
}
}
&.not-ml {
&_info {
margin-top: 6rpx;
display: flex;
align-items: center;
margin-left: 80rpx;
}
}
&_info {
margin-top: 6rpx;
display: flex;
align-items: center;
margin-left: 80rpx;
}
}
</style>
</style>
+207 -217
View File
@@ -3,13 +3,8 @@
<!-- 顶部区域 -->
<view class="comment-list_head">
<view class="title">
评论列表
<text class="count">{{ result.total || 0 }}</text>
</view>
<view class="filter">
<text class="filter-item " :class="{ active: sort == 0 }" @click="fnOnSort(0)">默认</text>
<text class="filter-item " :class="{ active: sort == 1 }" @click="fnOnSort(1)">热评</text>
<!-- <text class="filter-item">全部</text> -->
<text>评论列表</text>
<text class="count">{{ (result&& result.total) || 0 }}</text>
</view>
</view>
<!-- 内容区域 -->
@@ -21,62 +16,44 @@
</view>
<view v-else-if="loading == 'error'" class="error">
<tm-empty icon="icon-wind-cry" label="加载失败">
<tm-button theme="bg-gradient-light-blue-accent" size="m" v-if="!disallowComment" @click="fnToComment()">刷新试试</tm-button>
<tm-button theme="bg-gradient-light-blue-accent" size="m" v-if="!disallowComment"
@click="fnToComment()">刷新试试</tm-button>
</tm-empty>
</view>
</view>
<block v-else>
<tm-alerts
v-if="disallowComment && dataList.length !== 0"
color="red"
text
:margin="[0, 0]"
:shadow="0"
label="Ծ‸Ծ博主已设置该文章禁止评论!"
:round="3"
></tm-alerts>
<tm-alerts v-if="disallowComment && dataList.length !== 0" color="red" text :margin="[0, 0]" :shadow="0"
label="Ծ‸Ծ博主已设置该文章禁止评论!" :round="3"></tm-alerts>
<view class="empty pt-50" v-if="dataList.length == 0">
<tm-empty v-if="disallowComment" icon="icon-shiliangzhinengduixiang-" label="暂无评论">
<text class="text-red text-size-s">- 文章已开启禁止评论 -</text>
</tm-empty>
<tm-empty v-else icon="icon-shiliangzhinengduixiang-" label="暂无评论">
<tm-button theme="light-blue" :dense="true" :shadow="0" size="m" @click="fnToComment(null)">抢沙发</tm-button>
<tm-button theme="light-blue" :dense="true" :shadow="0" size="m"
@click="fnToComment(null)">抢沙发</tm-button>
</tm-empty>
</view>
<block v-else>
<!-- 评论内容 : 目前仅支持二级评论 -->
<block v-for="(comment, index) in dataList" :key="comment.id">
<comment-item
:useContentBg="false"
:isChild="false"
:comment="comment"
:postId="postId"
:disallowComment="disallowComment"
@on-copy="fnCopyContent"
@on-comment="fnToComment"
@on-todo="fnToDo"
@on-detail="fnShowCommetnDetail"
></comment-item>
<block v-for="(comment, index) in dataList" :key="comment.metadata.name">
<comment-item :useContentBg="false" :isChild="false" :comment="comment" :postName="postName"
:disallowComment="disallowComment" @on-copy="fnCopyContent" @on-comment="fnToComment"
@on-todo="fnToDo" @on-detail="fnShowCommetnDetail"></comment-item>
<!-- 二级评论 -->
<block v-if="comment.children && comment.children.length != 0">
<block v-for="(childComment, childIndex) in comment.children" :key="childComment.id">
<comment-item
:useContentBg="false"
:isChild="true"
:comment="childComment"
:postId="postId"
:disallowComment="disallowComment"
@on-copy="fnCopyContent"
@on-comment="fnToComment"
@on-todo="fnToDo"
@on-detail="fnShowCommetnDetail"
></comment-item>
<block v-if="comment.replies && comment.replies.items.length != 0">
<block v-for="(childComment, childIndex) in comment.replies.items"
:key="childComment.metadata.name">
<comment-item :useContentBg="false" :isChild="true" :comment="childComment"
:postName="postName" :disallowComment="disallowComment" @on-copy="fnCopyContent"
@on-comment="fnToComment" @on-todo="fnToDo"
@on-detail="fnShowCommetnDetail"></comment-item>
</block>
</block>
</block>
<view v-if="false" class="to-more-comment">
<tm-button item-class="btn" :block="true" width="90vw" theme="bg-gradient-light-blue-lighten" size="m">点击查看全部评论</tm-button>
<tm-button item-class="btn" :block="true" width="90vw" theme="bg-gradient-light-blue-lighten"
size="m">点击查看全部评论</tm-button>
</view>
</block>
</block>
@@ -85,198 +62,211 @@
</template>
<script>
import tmEmpty from '@/tm-vuetify/components/tm-empty/tm-empty.vue';
import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
import tmAlerts from '@/tm-vuetify/components/tm-alerts/tm-alerts.vue';
import tmEmpty from '@/tm-vuetify/components/tm-empty/tm-empty.vue';
import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
import tmAlerts from '@/tm-vuetify/components/tm-alerts/tm-alerts.vue';
export default {
name: 'comment-list',
components: { tmEmpty, tmButton, tmAlerts },
props: {
// 是否禁用评论
disallowComment: {
type: Boolean,
default: false
export default {
name: 'comment-list',
components: {
tmEmpty,
tmButton,
tmAlerts
},
postId: {
type: Number,
default: null
},
post: {
type: Object,
default: () => {}
}
},
data() {
return {
loading: 'loading',
sort: 0,
queryParams: {
sort: '',
more: true
props: {
// 是否禁用评论
disallowComment: {
type: Boolean,
default: false
},
api: 'getPostCommentTree',
result: {},
dataList: []
};
},
created() {
this.fnGetData();
uni.$on('comment_list_refresh', () => {
this.fnOnSort(this.sort, true);
});
},
methods: {
fnOnSort(type, refresh = false) {
if (this.sort == type && refresh == false) return;
const _api = ['getPostCommentTree', 'getPostTopCommentList'];
this.sort = type;
this.api = _api[type];
this.fnGetData();
postName: {
type: String,
default: ""
},
post: {
type: Object,
default: () => {}
}
},
fnGetData() {
this.loading = 'loading';
this.$httpApi[this.api](this.postId, {})
.then(res => {
if (res.status == 200) {
this.result = res.data;
this.dataList = res.data.content;
data() {
return {
loading: 'loading',
queryParams: {
group: "content.halo.run",
kind: "Post",
version: "v1alpha1",
name: "",
page: 1,
size: 50,
withReplies: true,
replySize: 10
},
result: null,
dataList: []
};
},
created() {
this.queryParams.name = this.postName;
this.fnGetData();
uni.$on('comment_list_refresh', () => {
this.fnOnSort(true);
});
},
methods: {
fnOnSort(refresh = false) {
if (refresh == false) return;
this.fnGetData();
},
fnGetData() {
this.loading = 'loading';
this.$httpApi.v2.getPostCommentList(this.queryParams)
.then(res => {
console.log("日志:", res)
this.result = res;
this.dataList = res.items;
this.loading = 'success';
this.$emit('on-loaded', this.dataList);
} else {
})
.catch(err => {
this.loading = 'error';
}
})
.catch(err => {
this.loading = 'error';
})
.finally(() => {
uni.hideLoading();
})
.finally(() => {
uni.hideLoading();
});
},
fnToDo() {
uni.$tm.toast('Halo暂未支持!');
},
fnToComment(data) {
if (this.disallowComment) {
return uni.$tm.toast('文章已禁止评论!');
}
console.log('data', data);
let _comment = {};
if (data) {
let {
type,
comment
} = data;
// 来自用户
_comment = {
isComment: false,
postName: comment.metadata.name,
title: comment.owner.displayName,
from: 'posts',
formPage: 'comment_list',
type: 'user'
};
} else {
// 来自文章
_comment = {
isComment: true,
postName: this.post.metadata.name,
title: '评论文章:' + this.post.spec.title,
formPage: 'comment_list',
from: 'posts',
type: 'post'
};
}
uni.$tm.vx.commit('comment/setCommentInfo', _comment);
this.$Router.push({
path: '/pagesA/comment/comment',
query: _comment
});
},
fnToDo() {
uni.$tm.toast('Halo暂未支持!');
},
fnToComment(data) {
if (this.disallowComment) {
return uni.$tm.toast('文章已禁止评论!');
}
console.log(data);
let _comment = {};
if (data) {
let { type, comment } = data;
// 来自用户
_comment = {
id: this.post.id,
parentId: comment.id,
title: comment.author,
from: 'posts',
formPage: 'comment_list',
type: 'user'
};
} else {
// 来自文章
_comment = {
id: this.post.id,
parentId: 0,
title: '评论文章:' + this.post.title,
formPage: 'comment_list',
from: 'posts',
type: 'post'
};
}
},
fnCopyContent(content) {
uni.$tm.u.setClipboardData(content);
uni.$tm.toast('内容已复制成功!');
},
uni.$tm.vx.commit('comment/setCommentInfo', _comment);
this.$Router.push({
path: '/pagesA/comment/comment',
query: _comment
});
},
fnCopyContent(content) {
uni.$tm.u.setClipboardData(content);
uni.$tm.toast('内容已复制成功!');
},
fnShowCommetnDetail(comment) {
this.$emit('on-comment-detail', {
postId: this.postId,
comment: comment
});
fnShowCommetnDetail(comment) {
this.$emit('on-comment-detail', {
postName: this.postName,
comment: comment
});
}
}
}
};
};
</script>
<style lang="scss" scoped>
.comment-list {
&_head {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
box-sizing: border-box;
padding-left: 24rpx;
font-size: 30rpx;
font-weight: bold;
.comment-list {
&_head {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
box-sizing: border-box;
padding-left: 24rpx;
font-size: 30rpx;
font-weight: bold;
&:before {
content: '';
position: absolute;
left: 0rpx;
top: 8rpx;
width: 8rpx;
height: 26rpx;
background-color: rgb(3, 174, 252);
border-radius: 6rpx;
}
.title {
.count {
font-size: 28rpx;
font-weight: normal;
&:before {
content: '';
position: absolute;
left: 0rpx;
top: 8rpx;
width: 8rpx;
height: 26rpx;
background-color: rgb(3, 174, 252);
border-radius: 6rpx;
}
}
.filter {
font-size: 26rpx;
font-weight: normal;
&-item {
margin-left: 20rpx;
color: #666;
&.active {
font-weight: bold;
color: rgb(255, 152, 0);
font-size: 26rpx;
.title {
.count {
font-size: 28rpx;
font-weight: normal;
}
}
.filter {
font-size: 26rpx;
font-weight: normal;
&-item {
margin-left: 20rpx;
color: #666;
&.active {
font-weight: bold;
color: rgb(255, 152, 0);
font-size: 26rpx;
}
}
}
}
}
&_content {
margin-top: 24rpx;
padding-bottom: 36rpx;
}
}
.loading-wrap {
width: 100%;
height: 506rpx;
.loading {
width: 100%;
}
.e-loading-icon {
font-size: 100rpx;
}
}
.to-more-comment {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-top: 80rpx;
::v-deep {
.tm-button .tm-button-btn uni-button {
height: 70rpx;
&_content {
margin-top: 24rpx;
padding-bottom: 36rpx;
}
}
}
</style>
.loading-wrap {
width: 100%;
height: 506rpx;
.loading {
width: 100%;
}
.e-loading-icon {
font-size: 100rpx;
}
}
.to-more-comment {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-top: 80rpx;
::v-deep {
.tm-button .tm-button-btn uni-button {
height: 70rpx;
}
}
}
</style>
+120 -133
View File
@@ -2,47 +2,31 @@
<!-- 轮播图 -->
<view class="Swiper-mfw-index-box">
<view class="Swiper-mfw-index Swiper-box" :class="[dotPosition]">
<swiper
class="Swiper-mfw"
:style="{ height: height }"
:circular="true"
:indicator-dots="false"
:autoplay="autoplay"
:interval="3000"
:duration="1000"
:current="currentIndex"
:disable-touch="disable_touch"
@change="change"
>
<swiper class="Swiper-mfw" :style="{ height: height }" :circular="true" :indicator-dots="false"
:autoplay="autoplay" :interval="3000" :duration="1000" :current="currentIndex"
:disable-touch="disable_touch" @change="change">
<!-- 只需要前5条数据 -->
<swiper-item class="swiper-mfw-item" v-if="index <= (dotPosition == 'right' ? 3 : 4)" v-for="(item, index) in list" :key="index">
<!-- /*
<block v-for="(item, index) in list" :key="index">
<swiper-item class="swiper-mfw-item" v-if="index <= 4">
<!-- /*
1. 这里不需要用api控制暂停视频
2. 因为video标签上加了v-if="current==index"
3. 当current == index时才会创建视频组件
4. 否current != index则就销毁视频
*/ -->
<!-- 如果有视频则显示视频-->
<template v-if="item.mp4 && current == index">
<video
class="ImageVideo"
:id="'ImageVideo' + index"
:ref="'ImageVideo' + index"
:src="item.mp4"
:loop="true"
:muted="false"
:autoplay="current == index ? true : false"
:controls="false"
:show-fullscreen-btn="false"
:show-play-btn="false"
:enable-progress-gesture="false"
:play-strategy="0"
:poster="item.image || item.src"
></video>
</template>
<!-- 否则显示图片 -->
<image v-else :src="item.image || item.src" class="Image" mode="aspectFill" @click.stop="$emit('on-click', item)"></image>
</swiper-item>
<!-- 如果有视频则显示视频-->
<template v-if="item.mp4 && current == index">
<video class="ImageVideo" :id="'ImageVideo' + index" :ref="'ImageVideo' + index"
:src="item.mp4" :loop="true" :muted="false" :autoplay="current == index ? true : false"
:controls="false" :show-fullscreen-btn="false" :show-play-btn="false"
:enable-progress-gesture="false" :play-strategy="0"
:poster="item.image || item.src"></video>
</template>
<!-- 否则显示图片 -->
<image v-else :src="item.image || item.src" class="Image" mode="aspectFill"
@click.stop="$emit('on-click', item)"></image>
</swiper-item>
</block>
</swiper>
<!-- 指示器 [Top] -->
<view v-if="useTop" class="Swiper-indicator-box indicator-Top-box">
@@ -84,12 +68,15 @@
<!-- 用户信息 -->
<view class="Bottom-UserInfo">
<!-- 头像 -->
<view class="UserImage-box"><image :src="item.avatar" class="Image" mode="aspectFill"></image></view>
<view class="UserImage-box">
<image :src="item.avatar" class="Image" mode="aspectFill"></image>
</view>
<!-- 用户名 -->
<view class="textbox UserName-box">
<text class="text UserInfo">{{ item.nickname }}</text>
</view>
<view v-if="item.createTime" class="jiange-box"><text class="text jiange-text"></text></view>
<view v-if="item.createTime" class="jiange-box"><text class="text jiange-text"></text>
</view>
<view v-if="item.createTime" class="textbox UserGPS-box">
<text class="text UserInfo">发布于 {{ item.createTime }}</text>
</view>
@@ -106,18 +93,14 @@
<!-- 左边 -->
<view class="Bottom-left-Imagelist">
<block v-for="(item, index) in list" :key="index">
<view
class="Bottom-item"
v-if="Number(index) <= (dotPosition == 'right' ? 3 : 4)"
:class="currentIndex == index ? 'current' : 'no'"
@click="SwiperIndTap(index)"
>
<view class="Bottom-item" v-if="Number(index) <= 4"
:class="currentIndex == index ? 'current' : 'no'" @click="SwiperIndTap(index)">
<image :src="item.image || item.src" class="Image" mode="aspectFill"></image>
</view>
</block>
</view>
<!-- 右边 -->
<view class="Bottom-right-lili-btn">
<view v-if="false" class="Bottom-right-lili-btn">
<view class="Bottom-item is-more">
<view class="more" @click.stop="$emit('on-more')">
MORE
@@ -132,102 +115,106 @@
</template>
<script>
export default {
name: 'e-swiper',
props: {
title: {
type: String,
default: ''
},
height: {
type: String,
default: '450rpx'
},
dotPosition: {
type: String,
default: 'bottom'
},
useTop: {
type: Boolean,
default: true
},
useDot: {
type: Boolean,
default: true
},
useTitle: {
type: Boolean,
default: true
},
useUser: {
type: Boolean,
default: true
},
// 轮播图 数据列表
list: {
type: Array,
default: () => []
},
// 当前选中的项(指示器坐标位置)
current: {
type: Number,
default: 0
},
// 是否自动轮播
autoplay: {
type: Boolean,
default: false
}
},
data() {
return {
// 是否禁止用户 touch 操作
currentIndex: 0,
disable_touch: false, //touch 用户划动引起swiper变化。
date: {
year: '-',
monthEn: '-',
month: '-'
export default {
name: 'e-swiper',
props: {
title: {
type: String,
default: ''
},
height: {
type: String,
default: '450rpx'
},
dotPosition: {
type: String,
default: 'bottom'
},
useTop: {
type: Boolean,
default: true
},
useDot: {
type: Boolean,
default: true
},
useTitle: {
type: Boolean,
default: true
},
useUser: {
type: Boolean,
default: true
},
// 轮播图 数据列表
list: {
type: Array,
default: () => []
},
// 当前选中的项(指示器坐标位置)
current: {
type: Number,
default: 0
},
// 是否自动轮播
autoplay: {
type: Boolean,
default: false
}
};
},
created() {
this.currentIndex = this.current;
const date = new Date();
//将月份名称存储在数组中
const monthArray = new Array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
},
data() {
return {
// 是否禁止用户 touch 操作
currentIndex: 0,
disable_touch: false, //touch 用户划动引起swiper变化。
date: {
year: '-',
monthEn: '-',
month: '-'
}
};
},
created() {
this.currentIndex = this.current;
const date = new Date();
//将月份名称存储在数组中
const monthArray = new Array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov',
'Dec');
this.date.year = date.getFullYear();
let month = date.getMonth() + 1;
this.date.month = month < 10 ? '0' + month : month;
this.date.monthEn = monthArray[date.getMonth()].toUpperCase();
},
methods: {
// current 改变时会触发 change 事件,event.detail = {current: current, source: source}
change(e) {
let { current, source } = e.detail;
//只有页面自动切换,手动切换时才轮播,其他不允许
if (source === 'autoplay' || source === 'touch') {
this.date.year = date.getFullYear();
let month = date.getMonth() + 1;
this.date.month = month < 10 ? '0' + month : month;
this.date.monthEn = monthArray[date.getMonth()].toUpperCase();
},
methods: {
// current 改变时会触发 change 事件,event.detail = {current: current, source: source}
change(e) {
let {
current,
source
} = e.detail;
//只有页面自动切换,手动切换时才轮播,其他不允许
if (source === 'autoplay' || source === 'touch') {
let event = {
current: current
};
this.currentIndex = current;
this.$emit('change', event);
}
},
// 手动点击了指示器[小图模式]
SwiperIndTap(e) {
let index = e;
let event = {
current: current
current: index
};
this.currentIndex = current;
this.currentIndex = index;
this.$emit('change', event);
}
},
// 手动点击了指示器[小图模式]
SwiperIndTap(e) {
let index = e;
let event = {
current: index
};
this.currentIndex = index;
this.$emit('change', event);
}
}
};
};
</script>
<style lang="scss" scoped>
@import './e-swiper.scss';
</style>
@import './e-swiper.scss';
</style>