Files
lucky_shop/components-diy/diy-channel-list.vue

332 lines
7.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view :style="[componentStyle, { '--row-count': value.rowCount }]">
<!-- 固定布局模式 -->
<view v-if="value.showStyle == 'fixed'" :class="['channel-list', 'row1-of' + value.rowCount]">
<view v-for="(item, index) in value.list" :key="index" class="channel-item">
<diy-channel-video
:value="item"
@video-play="playVideo(item)"
:list-mode="true"
:video-height="value.rowCount === 3 ? 180 : 240"
:title-line-clamp="value.titleLineClamp"
:show-play-btn="value.showPlayBtn"
:cover-style="value.coverStyle"
:play-btn-style="value.playBtnStyle"
/>
</view>
</view>
<!-- 其他布局模式 -->
<scroll-view v-else :class="['channel-nav', value.showStyle == 'fixed' ? 'fixed-layout' : value.showStyle]"
:scroll-x="value.showStyle == 'singleSlide'">
<view class="uni-scroll-view-content">
<view v-for="(item, index) in value.list" :key="index" :class="['channel-nav-item', value.mode]">
<diy-channel-video
:value="item"
@video-play="playVideo(item)"
:list-mode="true"
:video-height="value.rowCount === 3 ? 180 : 240"
:title-line-clamp="value.titleLineClamp"
:show-play-btn="value.showPlayBtn"
:cover-style="value.coverStyle"
:play-btn-style="value.playBtnStyle"
/>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
import DiyMinx from './minx.js'
import { wechatChannelUtil, wechatChannelConfig } from './js/wechat-channel.js'
/**
* 微信视频号列表组件
* 支持多种布局模式,包括固定布局和滚动布局
* 可配置列数、视频高度、标题行数等属性
*/
export default {
name: 'diy-channel-list',
props: {
/**
* 组件配置数据
* @type {Object}
* @default () => ({})
* @property {string} showStyle - 显示样式可选值fixed, singleSlide
* @property {number} rowCount - 每行显示的视频数量
* @property {Array} list - 视频列表数据
* @property {string} componentBgColor - 组件背景色
* @property {string} componentAngle - 组件圆角类型
* @property {number} topAroundRadius - 顶部圆角半径
* @property {number} bottomAroundRadius - 底部圆角半径
* @property {Object} ornament - 装饰效果配置
* @property {number} titleLineClamp - 标题显示行数
* @property {boolean} showPlayBtn - 是否显示播放按钮
* @property {Object} coverStyle - 视频封面图样式
* @property {Object} playBtnStyle - 播放按钮样式
*/
value: {
type: Object,
default: () => ({})
}
},
mixins: [DiyMinx],
data() {
return {
pageWidth: '',
indicatorDots: false,
swiperCurrent: 0
}
},
created() {
// 组件创建时的逻辑
},
watch: {
componentRefresh(newValue) {
// 监听组件刷新
}
},
computed: {
/**
* 组件样式
* 根据配置动态生成样式字符串
* @returns {string}
*/
componentStyle() {
let style = '';
if (this.value?.componentBgColor) {
style += 'background-color:' + this.value?.componentBgColor + ';';
}
if (this.value?.componentAngle == 'round') {
style += 'border-top-left-radius:' + (2 * this.value?.topAroundRadius) + 'rpx;';
style += 'border-top-right-radius:' + (2 * this.value?.topAroundRadius) + 'rpx;';
style += 'border-bottom-left-radius:' + (2 * this.value?.bottomAroundRadius) + 'rpx;';
style += 'border-bottom-right-radius:' + (2 * this.value?.bottomAroundRadius) + 'rpx;';
}
style += 'box-shadow:' + (this.value?.ornament?.type == 'shadow' ? '0 0 10rpx ' + this.value?.ornament?.color : '') + ';';
style += 'border:' + (this.value?.ornament?.type == 'stroke' ? '2rpx solid ' + this.value?.ornament?.color : '') + ';';
return style;
},
/**
* 轮播高度
* 根据模式和配置计算轮播高度
* @returns {string}
*/
swiperHeight() {
let height = 0;
if (this.value?.mode == 'graphic') {
height = (49 + this.value?.imageSize) * this.value?.pageCount;
} else if (this.value?.mode == 'img') {
height = (22 + this.value?.imageSize) * this.value?.pageCount;
} else if (this.value?.mode == 'text') {
height = 43 * this.value?.pageCount;
}
return 'height:' + (2 * height) + 'rpx';
},
/**
* 是否显示指示器
* 根据轮播配置和列表长度判断是否显示指示器
* @returns {boolean}
*/
isIndicatorDots() {
return this.value?.carousel?.type != 'hide' &&
1 != Math.ceil(this.value?.list?.length / (this.value?.pageCount * this.value?.rowCount));
}
},
methods: {
/**
* 播放视频
* 触发 video-play 事件,并在微信小程序中调用视频播放接口
* @param {Object} item - 视频数据对象
*/
async playVideo(item) {
await this.__$emitEvent({
eventName: 'video-play', data: item, promiseCallback: async (event, handler, awaitedResult) => {
if (!awaitedResult) return;
try {
// #ifdef MP-WEIXIN
await wechatChannelUtil.playVideo(item);
// #endif
} catch (err) {
console.error('打开视频号失败', err);
}
}
})
},
/**
* 图片加载错误处理
* 当图片加载失败时,设置默认图片
* @param {number} index - 图片索引
*/
imgError(index) {
// 图片加载失败的处理逻辑
console.log('图片加载失败:', index);
// 为失败的图片设置默认图片
const item = this.value.list[index];
if (item) {
// 使用默认图片替代加载失败的图片
// #ifdef MP-WEIXIN
item.coverUrl = wechatChannelConfig.video.defaultCoverUrl;
// #endif
}
}
}
}
</script>
<style lang="scss" scoped>
@import './css/common-channel.scss';
/**
* 列表布局样式
* 支持 2 列和 3 列布局
*/
.channel-list {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
padding: 16rpx;
box-sizing: border-box;
.channel-item {
flex: 0 0 calc(33.3333333% - 10rpx);
box-sizing: border-box;
&:nth-child(3n) {
margin-right: 0;
}
}
// 2 列布局
&.row1-of2 {
.channel-item {
flex: 0 0 calc(50% - 8rpx);
&:nth-child(3n) {
margin-right: 16rpx;
}
&:nth-child(2n) {
margin-right: 0;
}
}
}
}
/**
* 导航布局样式
* 支持固定布局和滚动布局
*/
.channel-nav {
padding: 16rpx;
box-sizing: border-box;
.uni-scroll-view-content {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
}
// 单滑动模式
&.singleSlide {
.uni-scroll-view-content {
flex-wrap: nowrap;
}
.channel-nav-item {
flex-shrink: 0;
width: 280rpx;
}
}
.channel-nav-item {
display: flex;
flex-direction: column;
box-sizing: border-box;
flex: 0 0 calc(33.3333333% - 10rpx);
&:nth-child(3n) {
margin-right: 0;
}
}
// 2 列布局
&.row1-of2 {
.channel-nav-item {
flex: 0 0 calc(50% - 8rpx);
&:nth-child(3n) {
margin-right: 16rpx;
}
&:nth-child(2n) {
margin-right: 0;
}
}
}
}
/**
* 确保所有视频卡片高度一致
*/
.channel-item, .channel-nav-item {
display: flex;
flex-direction: column;
}
/**
* 响应式调整
* 在小屏幕设备上调整布局和间距
*/
@media (max-width: 375px) {
.channel-list,
.channel-nav {
gap: 12rpx;
padding: 12rpx;
.channel-item,
.channel-nav-item {
flex: 0 0 calc(33.3333333% - 8rpx);
&:nth-child(3n) {
margin-right: 0;
}
}
// 小屏幕上的 2 列布局
&.row1-of2 {
.channel-item,
.channel-nav-item {
flex: 0 0 calc(50% - 6rpx);
&:nth-child(3n) {
margin-right: 12rpx;
}
&:nth-child(2n) {
margin-right: 0;
}
}
}
}
// 小屏幕上的单滑动模式
.channel-nav {
&.singleSlide {
.channel-nav-item {
width: 240rpx;
}
}
}
}
</style>