添加注释
parent
e4477da8e6
commit
6d7b17576f
|
|
@ -48,9 +48,20 @@
|
|||
const animation = uni.requireNativePlugin('animation');
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* 预定义的颜色数组,用于点赞动画元素的颜色随机选择
|
||||
*/
|
||||
const COLORS = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4', '#feca57', '#ff9ff3', '#ff5252', '#66bb6a'];
|
||||
|
||||
/**
|
||||
* 预定义的图标数组,用于点赞动画元素的图标随机选择
|
||||
*/
|
||||
const ICONS = [];
|
||||
|
||||
/**
|
||||
* 点赞动画效果组件
|
||||
* 实现类似直播中点赞的效果,包括飘心动画和连击数字提示
|
||||
*/
|
||||
export default {
|
||||
name: 'SimpleLikeEffect',
|
||||
props: {
|
||||
|
|
@ -67,31 +78,80 @@
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
/**
|
||||
* 存储所有点赞动画元素的数组
|
||||
*/
|
||||
like_list: [],
|
||||
// 连续点赞相关数据
|
||||
/**
|
||||
* 连续点赞计数
|
||||
*/
|
||||
like_count: 0,
|
||||
/**
|
||||
* 是否显示点赞计数
|
||||
*/
|
||||
show_like_count: false,
|
||||
/**
|
||||
* 点赞计数显示位置
|
||||
*/
|
||||
like_count_position: { x: 0, y: 0 },
|
||||
/**
|
||||
* 点赞计数文字颜色
|
||||
*/
|
||||
like_count_color: '#ff6b6b',
|
||||
/**
|
||||
* 点赞计数透明度
|
||||
*/
|
||||
like_count_opacity: 1,
|
||||
/**
|
||||
* 点赞计数缩放比例
|
||||
*/
|
||||
like_count_scale: 1,
|
||||
/**
|
||||
* 上次点赞的时间戳
|
||||
*/
|
||||
last_like_time: 0,
|
||||
/**
|
||||
* 点赞计数隐藏定时器
|
||||
*/
|
||||
like_count_timer: null,
|
||||
/**
|
||||
* 重置计数的定时器
|
||||
*/
|
||||
reset_timer: null, // 重置计数的定时器
|
||||
/**
|
||||
* 上次点击时间,用于防抖处理
|
||||
*/
|
||||
last_click_time: 0 // 防止双击添加多个图标
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 合并默认图标和自定义图标
|
||||
/**
|
||||
* 可用的图标集合,合并了默认图标和外部传入的自定义图标
|
||||
* @returns {Array} 图标数组
|
||||
*/
|
||||
available_icons() {
|
||||
return [...ICONS, ...this.propCustomIcons];
|
||||
},
|
||||
// 合并默认图片和自定义图片
|
||||
/**
|
||||
* 可用的图片集合,来自外部传入的自定义图片
|
||||
* @returns {Array} 图片数组
|
||||
*/
|
||||
available_images() {
|
||||
return this.propCustomImages;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 添加点赞动画元素
|
||||
* @param {Object} event - 点击事件对象,用于获取点击坐标
|
||||
* @param {Object} options - 可选配置参数
|
||||
* @param {String} options.image_src - 自定义图片路径
|
||||
* @param {String} options.icon - 自定义图标字符
|
||||
* @param {String} options.color - 自定义颜色
|
||||
*/
|
||||
add_like(event, options = {}) {
|
||||
// 防抖处理,防止双击添加多个图标
|
||||
const now = Date.now();
|
||||
|
|
@ -183,11 +243,21 @@
|
|||
this.handle_like_count(x, y, color);
|
||||
},
|
||||
|
||||
/**
|
||||
* 移除指定的点赞元素
|
||||
* @param {Number|String} id - 要移除的点赞元素ID
|
||||
*/
|
||||
remove_like(id) {
|
||||
this.like_list = this.like_list.filter(item => item.id !== id);
|
||||
},
|
||||
|
||||
// 处理连续点赞数量提示
|
||||
/**
|
||||
* 处理连续点赞数量提示
|
||||
* 当用户连续点赞时显示连击数
|
||||
* @param {Number} x - 点击位置的x坐标
|
||||
* @param {Number} y - 点击位置的y坐标
|
||||
* @param {String} color - 数字提示颜色
|
||||
*/
|
||||
handle_like_count(x, y, color) {
|
||||
const current_time = Date.now();
|
||||
|
||||
|
|
@ -248,7 +318,9 @@
|
|||
}, 1200);
|
||||
},
|
||||
|
||||
// 隐藏数量提示
|
||||
/**
|
||||
* 隐藏点赞数量提示
|
||||
*/
|
||||
hide_like_count() {
|
||||
// #ifdef APP-NVUE
|
||||
const ref = this.$refs['likeCount'];
|
||||
|
|
@ -274,7 +346,10 @@
|
|||
// #endif
|
||||
},
|
||||
|
||||
// 点赞项动画
|
||||
/**
|
||||
* 执行单个点赞元素的动画效果
|
||||
* @param {Number|String} id - 点赞元素ID
|
||||
*/
|
||||
animate_like_item(id) {
|
||||
// #ifdef APP-NVUE
|
||||
const ref = this.$refs['likeItem' + id];
|
||||
|
|
@ -323,7 +398,9 @@
|
|||
// #endif
|
||||
},
|
||||
|
||||
// 数量提示动画
|
||||
/**
|
||||
* 执行点赞数量提示的动画效果
|
||||
*/
|
||||
animate_like_count() {
|
||||
// #ifdef APP-NVUE
|
||||
const ref = this.$refs['likeCount'];
|
||||
|
|
@ -347,6 +424,11 @@
|
|||
}
|
||||
// #endif
|
||||
},
|
||||
/**
|
||||
* 更加健壮的数组检查方法
|
||||
* @param {*} data - 待检测的数据
|
||||
* @returns {Boolean} 是否为数组
|
||||
*/
|
||||
// 更加健壮的数组检查方法
|
||||
is_array(data) {
|
||||
return Array.isArray(data) || data instanceof Array || (data && typeof data === 'object' && data.length !== undefined);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<template>
|
||||
<view v-if="!is_loading" class="flex-row align-c jc-c pa-20 box-border-box oh bg-f9" :style="good_style">
|
||||
<block v-if="good_list.length > 0">
|
||||
<!-- 固定在顶部的商品操作栏 -->
|
||||
<view class="goods-header-fixed" :style="'width:' + windowWidth + 'px;'">
|
||||
<view class="flex-row align-c jc-e pa-10">
|
||||
<view class="flex-col" @tap="goods_order">
|
||||
|
|
@ -23,6 +24,7 @@
|
|||
<scroll-view scroll-y class="scroll-type" :style="good_style + (propIsGoodsPopup ? 'padding-bottom: 20rpx;' : '' )" :show-scrollbar="false">
|
||||
<view v-for="(item, index) in good_list" :key="item.id">
|
||||
<!-- #endif -->
|
||||
<!-- 商品项 -->
|
||||
<view :class="'goods-item flex-row align-c box-border-box' + (item.id == explanation_id ? ' bg-red-light' : '')" :style="'width:' + (windowWidth - 24) + 'px;'" :data-index="index" :data-value="item.checkbox" :data-url="item.goods_url" @tap="goods_detail">
|
||||
<view class="flex-1">
|
||||
<view class="flex-row align-c">
|
||||
|
|
@ -33,8 +35,9 @@
|
|||
<!-- #ifdef APP-NVUE -->
|
||||
<image :class="propIsGoodsPopup ? 'goods-item-popup-image' : 'goods-item-image'" :src="item.images" mode="aspectFit"></image>
|
||||
<!-- #endif -->
|
||||
<!-- 商品序号标识 -->
|
||||
<text class="image-top-index">{{ index + 1 }}</text>
|
||||
<!-- 音乐进度条 -->
|
||||
<!-- 正在讲解中的商品音乐进度条 -->
|
||||
<view v-if="item.id == explanation_id" class="music-progress-container flex-row align-c jc-c" :style="propIsGoodsPopup ? 'width: 200rpx;' : 'width: 120rpx;'">
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<view class="music-progress-bars mr-5">
|
||||
|
|
@ -53,6 +56,7 @@
|
|||
<text class="size-12 cr-f">讲解中</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 商品信息区域 -->
|
||||
<view class="ml-10 flex-1 flex-col jc-sb goods-item-popup-content">
|
||||
<text class="goods-item-title text-line-2">{{ item.title }}</text>
|
||||
<view class="flex-1 mt-10">
|
||||
|
|
@ -68,6 +72,7 @@
|
|||
<text class="mr-5 size-14 cr-9">库存</text>
|
||||
<text class="goods-item-inventory size-14 cr-9">{{ item.inventory }}</text>
|
||||
</view>
|
||||
<!-- 购买按钮 -->
|
||||
<button type="primary" class="btn-block cr-main bg-main mr-0 ml-0 flex-row align-c jc-c pa-5" style="width: 100rpx;height:48rpx;border-radius: 10rpx" :data-id="item.id" :data-url="item.goods_url" @tap="goods_detail"><text class="size-14 cr-f">购买</text></button>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -89,6 +94,7 @@
|
|||
<!-- #endif -->
|
||||
</block>
|
||||
<block v-else>
|
||||
<!-- 无商品时的提示 -->
|
||||
<view class="flex-1 flex-col align-c">
|
||||
<text class="tip-title">暂无商品</text>
|
||||
</view>
|
||||
|
|
@ -101,6 +107,10 @@ import componentIcon from "@/pages/plugins/live/pull/components/icon/icon.vue";
|
|||
import componentBottomLine from '@/components/bottom-line/bottom-line.vue';
|
||||
const app = getApp();
|
||||
|
||||
/**
|
||||
* 商品展示组件
|
||||
* 用于直播间商品列表展示,支持普通页面和弹窗两种模式
|
||||
*/
|
||||
export default {
|
||||
name: 'Goods',
|
||||
components: {
|
||||
|
|
@ -108,11 +118,17 @@ export default {
|
|||
componentBottomLine
|
||||
},
|
||||
props: {
|
||||
// isGoodsPopup 是否是商品弹出框,弹出框一般是用在直播页显示的商品列表,直播开始前isGoodsPopup是false,显示的是一整个页面
|
||||
/**
|
||||
* 是否是商品弹出框
|
||||
* 弹出框一般是用在直播页显示的商品列表,直播开始前isGoodsPopup是false,显示的是一整个页面
|
||||
*/
|
||||
propIsGoodsPopup: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/**
|
||||
* 直播间ID
|
||||
*/
|
||||
propLiveRoomId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
|
|
@ -153,6 +169,10 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
//#region 设置页面屏幕大小
|
||||
/**
|
||||
* 商品区域样式
|
||||
* 根据是否为弹出框模式计算不同的宽高
|
||||
*/
|
||||
good_style() {
|
||||
// 判断是否是弹出框形式
|
||||
if (!this.propIsGoodsPopup) {
|
||||
|
|
@ -172,7 +192,10 @@ export default {
|
|||
watch: {
|
||||
//#region 音乐进度条相关逻辑
|
||||
// #ifdef APP-NVUE
|
||||
// 监听正在讲解的商品ID变化
|
||||
/**
|
||||
* 监听正在讲解的商品ID变化
|
||||
* 当商品讲解状态发生变化时,控制音频动画的播放和停止
|
||||
*/
|
||||
explanation_id: {
|
||||
handler(newVal, oldVal) {
|
||||
// 先停止所有动画
|
||||
|
|
@ -216,6 +239,10 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
//#region 初始化
|
||||
/**
|
||||
* 初始化商品列表
|
||||
* 请求服务器获取商品数据并更新界面
|
||||
*/
|
||||
init() {
|
||||
if (!this.propIsGoodsPopup) {
|
||||
this.is_loading = true;
|
||||
|
|
@ -266,7 +293,11 @@ export default {
|
|||
//#endregion
|
||||
|
||||
//#region 商品列表处理
|
||||
// 讲解商品
|
||||
/**
|
||||
* 控制商品讲解状态
|
||||
* 点击商品时切换其讲解状态,已讲解则取消讲解,未讲解则设为讲解中
|
||||
* @param {Object} e 事件对象
|
||||
*/
|
||||
explanation(e) {
|
||||
// 讲解商品
|
||||
const id = e.currentTarget.dataset.id;
|
||||
|
|
@ -280,7 +311,12 @@ export default {
|
|||
|
||||
//#region 音乐进度条相关逻辑
|
||||
// #ifdef APP-NVUE
|
||||
// 高度动态变化的动画(与vue平台CSS动画频率一致)
|
||||
/**
|
||||
* 启动第一个音频条动画
|
||||
* 实现1.1秒周期的高度变化动画效果
|
||||
* @param {Object} barRef 条形元素引用
|
||||
* @param {Number} delay 动画延迟时间(ms)
|
||||
*/
|
||||
start_nvue_height_animation(barRef, delay) {
|
||||
if (!barRef) return;
|
||||
|
||||
|
|
@ -362,7 +398,12 @@ export default {
|
|||
this.animationTimers.push(timer);
|
||||
},
|
||||
|
||||
// 为第二个条形定义动画序列(1.4s周期)
|
||||
/**
|
||||
* 启动第二个音频条动画
|
||||
* 实现1.4秒周期的高度变化动画效果
|
||||
* @param {Object} barRef 条形元素引用
|
||||
* @param {Number} delay 动画延迟时间(ms)
|
||||
*/
|
||||
start_nvue_height_animation2(barRef, delay) {
|
||||
if (!barRef) return;
|
||||
|
||||
|
|
@ -415,7 +456,12 @@ export default {
|
|||
this.animationTimers.push(timer);
|
||||
},
|
||||
|
||||
// 为第三个条形定义动画序列(0.9s周期)
|
||||
/**
|
||||
* 启动第三个音频条动画
|
||||
* 实现0.9秒周期的高度变化动画效果
|
||||
* @param {Object} barRef 条形元素引用
|
||||
* @param {Number} delay 动画延迟时间(ms)
|
||||
*/
|
||||
start_nvue_height_animation3(barRef, delay) {
|
||||
if (!barRef) return;
|
||||
|
||||
|
|
@ -462,6 +508,10 @@ export default {
|
|||
this.animationTimers.push(timer);
|
||||
},
|
||||
|
||||
/**
|
||||
* 停止所有NVUE动画
|
||||
* 清除动画定时器并重置所有音频条到初始状态
|
||||
*/
|
||||
stop_nvue_animation() {
|
||||
// 清除所有定时器
|
||||
this.animationTimers.forEach(timer => {
|
||||
|
|
@ -488,21 +538,40 @@ export default {
|
|||
},
|
||||
// #endif
|
||||
//#endregion
|
||||
// 购买商品
|
||||
|
||||
/**
|
||||
* 查看商品详情
|
||||
* 点击商品图片或购买按钮时跳转到商品详情页
|
||||
* @param {Object} e 事件对象
|
||||
*/
|
||||
goods_detail(e) {
|
||||
const url = e.currentTarget.dataset.url + '&live_room_id=1';
|
||||
app.globalData.url_open(url);
|
||||
},
|
||||
// 订单
|
||||
|
||||
/**
|
||||
* 查看订单
|
||||
* 点击订单图标时跳转到用户订单页面
|
||||
* @param {Object} e 事件对象
|
||||
*/
|
||||
goods_order (e) {
|
||||
console.log('查看订单');
|
||||
app.globalData.url_open('/pages/user-order/user-order');
|
||||
},
|
||||
// 购物车
|
||||
|
||||
/**
|
||||
* 查看购物车
|
||||
* 点击购物车图标时跳转到购物车页面
|
||||
* @param {Object} e 事件对象
|
||||
*/
|
||||
goods_cart (e) {
|
||||
console.log('查看购物车');
|
||||
app.globalData.url_open('/pages/cart-page/cart-page');
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回上一页
|
||||
*/
|
||||
back() {
|
||||
app.globalData.page_back_prev_event();
|
||||
}
|
||||
|
|
@ -711,5 +780,4 @@ export default {
|
|||
}
|
||||
}
|
||||
// #endif
|
||||
</style>
|
||||
|
||||
</style>
|
||||
|
|
@ -1,10 +1,25 @@
|
|||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<!-- 视频播放器容器 -->
|
||||
<view class="player-wrapper" :id="videoWrapperId" :randomNum="randomNum" :change:randomNum="hlsVideoPlayer.randomNumChange" :viewportProps="viewportProps" :change:viewportProps="hlsVideoPlayer.viewportChange" :videoSrc="videoSrc" :change:videoSrc="hlsVideoPlayer.initVideoPlayer" :command="eventCommand" :change:command="hlsVideoPlayer.triggerCommand" :func="renderFunc" :change:func="hlsVideoPlayer.triggerFunc" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* H5 HLS视频播放组件
|
||||
* 支持HLS流媒体播放和普通视频格式播放,兼容多种浏览器和移动端设备
|
||||
*/
|
||||
export default {
|
||||
/**
|
||||
* 组件属性
|
||||
* @property {String} propSrc - 视频源地址
|
||||
* @property {Boolean} propAutoplay - 是否自动播放
|
||||
* @property {Boolean} propControls - 是否显示控件
|
||||
* @property {String} propObjectFit - 视频填充方式
|
||||
* @property {Boolean} propMuted - 是否静音
|
||||
* @property {Number} propPlaybackRate - 播放速率
|
||||
* @property {String} propPoster - 视频封面图
|
||||
*/
|
||||
props: {
|
||||
propSrc: {
|
||||
type: String,
|
||||
|
|
@ -35,6 +50,16 @@
|
|||
default: ''
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 组件内部数据
|
||||
* @property {Number} randomNum - 随机数用于生成唯一ID
|
||||
* @property {String} videoSrc - 视频源地址
|
||||
* @property {Object} eventCommand - 视频原生事件指令
|
||||
* @property {Object} renderFunc - renderjs层函数执行指令
|
||||
* @property {Number} currentTime - 当前播放时间
|
||||
* @property {Number} duration - 视频总时长
|
||||
* @property {Boolean} playing - 是否正在播放
|
||||
*/
|
||||
data() {
|
||||
return {
|
||||
randomNum: Math.floor(Math.random() * 100000000),
|
||||
|
|
@ -52,9 +77,16 @@
|
|||
playing: false
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 数据监听器
|
||||
*/
|
||||
watch: {
|
||||
// 监听视频资源地址更新
|
||||
propSrc: {
|
||||
/**
|
||||
* 处理视频源地址变更
|
||||
* @param {String} val - 新的视频源地址
|
||||
*/
|
||||
handler(val) {
|
||||
if (!val) return
|
||||
setTimeout(() => {
|
||||
|
|
@ -64,11 +96,22 @@
|
|||
immediate: true
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 计算属性
|
||||
*/
|
||||
computed: {
|
||||
/**
|
||||
* 视频容器ID
|
||||
* @returns {String} 唯一的视频容器ID
|
||||
*/
|
||||
videoWrapperId() {
|
||||
return `video-wrapper-${this.randomNum}`
|
||||
},
|
||||
// 聚合视图层的所有数据变化,传给renderjs的渲染层
|
||||
/**
|
||||
* 视口属性集合
|
||||
* @returns {Object} 包含所有视口相关配置的对象
|
||||
*/
|
||||
viewportProps() {
|
||||
return {
|
||||
autoplay: this.propAutoplay,
|
||||
|
|
@ -80,28 +123,54 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
// 方法
|
||||
/**
|
||||
* 组件方法
|
||||
*/
|
||||
methods: {
|
||||
/**
|
||||
* 向父组件发送事件
|
||||
* @param {Object} options - 事件选项
|
||||
* @param {String} options.event - 事件名称
|
||||
* @param {*} [options.data] - 事件数据
|
||||
*/
|
||||
// 传递事件指令给父组件
|
||||
eventEmit({ event, data }) {
|
||||
this.$emit(event, data)
|
||||
},
|
||||
/**
|
||||
* 更新视图层数据
|
||||
* @param {Object} options - 数据选项
|
||||
* @param {String} options.key - 数据键名
|
||||
* @param {*} options.value - 数据值
|
||||
*/
|
||||
// 修改view视图层的data数据
|
||||
setViewData({ key, value }) {
|
||||
key && this.$set(this, key, value)
|
||||
},
|
||||
/**
|
||||
* 重置事件指令
|
||||
*/
|
||||
// 重置事件指令
|
||||
resetEventCommand() {
|
||||
this.eventCommand = null
|
||||
},
|
||||
/**
|
||||
* 发送播放指令
|
||||
*/
|
||||
// 播放指令
|
||||
play() {
|
||||
this.eventCommand = 'play'
|
||||
},
|
||||
/**
|
||||
* 发送暂停指令
|
||||
*/
|
||||
// 暂停指令
|
||||
pause() {
|
||||
this.eventCommand = 'pause'
|
||||
},
|
||||
/**
|
||||
* 重置自定义函数指令
|
||||
*/
|
||||
// 重置自定义函数指令
|
||||
resetFunc() {
|
||||
this.renderFunc = {
|
||||
|
|
@ -109,6 +178,10 @@
|
|||
params: null
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 移除视频
|
||||
* @param {*} params - 参数
|
||||
*/
|
||||
// 自定义事件 - 移除视频
|
||||
remove(params) {
|
||||
this.renderFunc = {
|
||||
|
|
@ -116,6 +189,10 @@
|
|||
params
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 全屏操作
|
||||
* @param {*} params - 参数
|
||||
*/
|
||||
// 自定义事件 - 全屏
|
||||
fullScreen(params) {
|
||||
this.renderFunc = {
|
||||
|
|
@ -123,6 +200,10 @@
|
|||
params
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 跳转到指定时间点
|
||||
* @param {Number} time - 时间点(秒)
|
||||
*/
|
||||
// 跳转到指定时间点
|
||||
toSeek(time) {
|
||||
this.renderFunc = {
|
||||
|
|
@ -135,9 +216,21 @@
|
|||
</script>
|
||||
|
||||
<script module="hlsVideoPlayer" lang="renderjs">
|
||||
/**
|
||||
* RenderJS模块 - HLS视频播放器核心逻辑
|
||||
* 在RenderJS环境中运行,负责实际的视频播放控制
|
||||
*/
|
||||
import hlsjs from '@/node_modules/hls.js/dist/hls.min.js'
|
||||
const PLAYER_ID = 'HLS_VIDEO_PLAYER'
|
||||
export default {
|
||||
/**
|
||||
* RenderJS数据
|
||||
* @property {String} num - 随机数标识符
|
||||
* @property {HTMLElement} videoEl - 视频元素引用
|
||||
* @property {Object} hlsPlayer - HLS播放器实例
|
||||
* @property {Object} renderProps - 渲染属性
|
||||
* @property {Boolean} autoplayRejected - 自动播放是否被拒绝
|
||||
*/
|
||||
data() {
|
||||
return {
|
||||
num: '',
|
||||
|
|
@ -147,19 +240,41 @@
|
|||
autoplayRejected: false // 标记自动播放是否被拒绝
|
||||
}
|
||||
},
|
||||
/**
|
||||
* RenderJS计算属性
|
||||
*/
|
||||
computed: {
|
||||
/**
|
||||
* 播放器ID
|
||||
* @returns {String} 唯一的播放器ID
|
||||
*/
|
||||
playerId() {
|
||||
return `${PLAYER_ID}_${this.num}`
|
||||
},
|
||||
/**
|
||||
* 容器ID
|
||||
* @returns {String} 视频容器ID
|
||||
*/
|
||||
wrapperId() {
|
||||
return `video-wrapper-${this.num}`
|
||||
}
|
||||
},
|
||||
/**
|
||||
* RenderJS方法
|
||||
*/
|
||||
methods: {
|
||||
/**
|
||||
* 判断是否为苹果设备
|
||||
* @returns {Boolean} 是否为苹果设备(iPhone或iPad)
|
||||
*/
|
||||
isApple() {
|
||||
const ua = navigator.userAgent.toLowerCase()
|
||||
return ua.indexOf('iphone') !== -1 || ua.indexOf('ipad') !== -1
|
||||
},
|
||||
/**
|
||||
* 初始化视频播放器
|
||||
* @param {String} src - 视频源地址
|
||||
*/
|
||||
async initVideoPlayer(src) {
|
||||
await this.$nextTick()
|
||||
if (!src) return
|
||||
|
|
@ -217,6 +332,11 @@
|
|||
this.attemptAutoPlay(videoEl, muted);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 尝试自动播放视频
|
||||
* @param {HTMLVideoElement} videoElement - 视频元素
|
||||
* @param {Boolean} isMuted - 是否静音
|
||||
*/
|
||||
// 尝试自动播放视频
|
||||
attemptAutoPlay(videoElement, isMuted) {
|
||||
const playPromise = videoElement.play();
|
||||
|
|
@ -242,6 +362,10 @@
|
|||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 初始化HLS播放器
|
||||
* @param {String} src - HLS流地址
|
||||
*/
|
||||
// 播放视频流
|
||||
initHlsPlayer(src) {
|
||||
if (hlsjs.isSupported()) {
|
||||
|
|
@ -277,6 +401,10 @@
|
|||
this.videoEl.src = src
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 监听视频相关事件
|
||||
* 注册各种视频事件监听器,包括播放、暂停、结束等
|
||||
*/
|
||||
// 监听视频相关事件
|
||||
listenVideoEvent() {
|
||||
// 播放事件监听
|
||||
|
|
@ -405,6 +533,10 @@
|
|||
document.addEventListener('fullscreenchange', fullscreenchangeHandler)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 销毁播放器实例
|
||||
* 清理HLS播放器和视频元素,释放资源
|
||||
*/
|
||||
// 销毁播放器实例
|
||||
destroyPlayer() {
|
||||
if (this.hlsPlayer) {
|
||||
|
|
@ -422,6 +554,10 @@
|
|||
// 重置自动播放标记
|
||||
this.autoplayRejected = false;
|
||||
},
|
||||
/**
|
||||
* 触发指令事件
|
||||
* @param {String} eventType - 事件类型(play/pause等)
|
||||
*/
|
||||
triggerCommand(eventType) {
|
||||
if (eventType) {
|
||||
this.$ownerInstance.callMethod('resetEventCommand')
|
||||
|
|
@ -434,6 +570,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 触发函数调用
|
||||
* @param {Object} func - 函数对象
|
||||
* @param {String} func.name - 函数名
|
||||
* @param {*} func.params - 函数参数
|
||||
*/
|
||||
triggerFunc(func) {
|
||||
const { name, params } = func || {}
|
||||
if (name) {
|
||||
|
|
@ -443,6 +585,9 @@
|
|||
this.$ownerInstance.callMethod('resetFunc')
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 移除视频处理器
|
||||
*/
|
||||
removeHandler() {
|
||||
this.destroyPlayer()
|
||||
this.$ownerInstance.callMethod('setViewData', {
|
||||
|
|
@ -450,6 +595,10 @@
|
|||
value: ''
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 全屏处理器
|
||||
* @param {*} params - 参数
|
||||
*/
|
||||
fullScreenHandler() {
|
||||
if (this.videoEl) {
|
||||
if (this.isApple()) {
|
||||
|
|
@ -463,11 +612,19 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 跳转时间点处理器
|
||||
* @param {Number} time - 时间点(秒)
|
||||
*/
|
||||
toSeekHandler(time) {
|
||||
if (this.videoEl) {
|
||||
this.videoEl.currentTime = time
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 视口变更处理
|
||||
* @param {Object} props - 视口属性
|
||||
*/
|
||||
viewportChange(props) {
|
||||
this.renderProps = props
|
||||
const { autoplay, muted, controls, playbackRate } = props
|
||||
|
|
@ -483,10 +640,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 随机数变更处理
|
||||
* @param {Number} val - 随机数
|
||||
*/
|
||||
randomNumChange(val) {
|
||||
this.num = val
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 组件销毁前钩子
|
||||
* 清理播放器资源
|
||||
*/
|
||||
// 组件销毁时清理资源
|
||||
beforeDestroy() {
|
||||
this.destroyPlayer()
|
||||
|
|
|
|||
|
|
@ -1,19 +1,24 @@
|
|||
<template>
|
||||
<view class="like-button">
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<!-- 在NVUE环境下使用list容器显示动画元素 -->
|
||||
<list class="animate-wrap">
|
||||
<!-- 循环渲染点赞动画元素 -->
|
||||
<cell class="a-img" v-for="(item,index) in viewList" :key="item.elId" :ref="item.elId" :style="{ 'right': propSite.x || propSite[0] + 'rpx', 'bottom': propSite.y || propSite[1] + 'rpx'}">
|
||||
<image :style="{ 'width': propImgWidth + 'rpx', 'height': propImgHeight + 'rpx'}" mode="widthFix" :src="item.src" :animation="item.animation"></image>
|
||||
</cell>
|
||||
</list>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<!-- 在非NVUE环境下使用view容器显示动画元素 -->
|
||||
<view class="animate-wrap">
|
||||
<!-- 循环渲染点赞动画元素 -->
|
||||
<view class="a-img" v-for="(item,index) in viewList" :key="item.elId" :ref="item.elId" :style="{ 'right': propSite.x || propSite[0] + 'rpx', 'bottom': propSite.y || propSite[1] + 'rpx'}">
|
||||
<image :style="{'width': propImgWidth + 'rpx', 'height': propImgHeight + 'rpx'}" mode="widthFix" :src="item.src" :animation="item.animation"></image>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- 点赞按钮区域 -->
|
||||
<view class="on-button">
|
||||
<view ref="likeBtn" id="like-btn" class="el-like-btn" @tap="handleClick">
|
||||
<slot></slot>
|
||||
|
|
@ -24,46 +29,101 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 点赞动画按钮组件
|
||||
* 实现点击按钮后产生飞出图标动画的效果,常用于直播场景中的点赞功能
|
||||
*/
|
||||
export default {
|
||||
props: {
|
||||
/**
|
||||
* 显示图标路径数组
|
||||
* @type {Array}
|
||||
* @default []
|
||||
*/
|
||||
propShowImgs: { // 显示图标路径
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 动画持续时间(毫秒)
|
||||
* @type {Number}
|
||||
* @default 5000
|
||||
*/
|
||||
propDuration: { // 动画效果时间
|
||||
type: Number,
|
||||
default: 5000
|
||||
},
|
||||
/**
|
||||
* X轴方向随机幅度范围
|
||||
* @type {Number}
|
||||
* @default 50
|
||||
*/
|
||||
propRange: { // x 间隔幅度
|
||||
type: Number,
|
||||
default: 50
|
||||
},
|
||||
/**
|
||||
* 图标飞行最大高度
|
||||
* @type {Number}
|
||||
* @default 200
|
||||
*/
|
||||
propHigh: { // 图标高度
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
/**
|
||||
* 组件宽度
|
||||
* @type {Number|String}
|
||||
* @default 52
|
||||
*/
|
||||
propWidth: { // 图标宽度
|
||||
type: Number || String,
|
||||
default: 52
|
||||
},
|
||||
/**
|
||||
* 组件高度
|
||||
* @type {Number|String}
|
||||
* @default 52
|
||||
*/
|
||||
propHeight: { // 图标高度
|
||||
type: Number || String,
|
||||
default: 52
|
||||
},
|
||||
/**
|
||||
* 图标宽度
|
||||
* @type {Number|String}
|
||||
* @default 52
|
||||
*/
|
||||
propImgWidth: { // 图标宽度
|
||||
type: Number || String,
|
||||
default: 52
|
||||
},
|
||||
/**
|
||||
* 图标高度
|
||||
* @type {Number|String}
|
||||
* @default 52
|
||||
*/
|
||||
propImgHeight: { // 图标高度
|
||||
type: Number || String,
|
||||
default: 52
|
||||
},
|
||||
/**
|
||||
* 点击节流时间(毫秒),防止过快点击
|
||||
* @type {Number}
|
||||
* @default 200
|
||||
*/
|
||||
propThrottle: { // 点击节流 ms
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
/**
|
||||
* 图标出现位置坐标
|
||||
* 可以是[x, y]数组或{x, y}对象格式
|
||||
* @type {Array|Object}
|
||||
* @default [122, 95]
|
||||
*/
|
||||
propSite: { // x y 坐标 [x<Number>, y<Number>]
|
||||
type: Array || Object,
|
||||
default: () => {
|
||||
|
|
@ -73,10 +133,20 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 是否启用缩放效果,可以设置为数字指定缩放倍数
|
||||
* @type {Number|Boolean}
|
||||
* @default false
|
||||
*/
|
||||
propLarge: { // 是否缩放冒泡
|
||||
type: [Number, Boolean],
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* 是否单独移除动画元素(true时逐个删除,false时统一删除)
|
||||
* @type {Boolean}
|
||||
* @default true
|
||||
*/
|
||||
propAlone: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
|
|
@ -84,17 +154,21 @@
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
viewList: [], // 渲染元素
|
||||
elId: 0, // 元素渲染id
|
||||
oldTime: 0, // 全局时间用于函数节流
|
||||
timer: null, // 定时器
|
||||
waitDeleteIndex: 0
|
||||
viewList: [], // 渲染元素列表
|
||||
elId: 0, // 元素渲染ID计数器
|
||||
oldTime: 0, // 上次点击时间戳,用于节流
|
||||
timer: null, // 定时器引用
|
||||
waitDeleteIndex: 0 // 等待删除的元素索引计数
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
methods: {
|
||||
/**
|
||||
* 处理点击事件,创建并播放点赞动画
|
||||
* @param {Event} e 点击事件对象
|
||||
*/
|
||||
handleClick(e) {
|
||||
// 函数节流
|
||||
// 函数节流,防止过快点击
|
||||
let interval = e.timeStamp - this.oldTime
|
||||
if (interval < this.propThrottle) return null;
|
||||
this.oldTime = e.timeStamp
|
||||
|
|
@ -103,7 +177,9 @@
|
|||
// #ifdef APP-NVUE
|
||||
animation = weex.requireModule('animation')
|
||||
// #endif
|
||||
// 随机选择一个图标
|
||||
let randomImg = Math.floor(Math.random() * this.propShowImgs.length)
|
||||
// 构造动画元素数据
|
||||
let _item = {
|
||||
elId: 'el_likeicon_' + this.elId, // 生成元素ref
|
||||
src: this.propShowImgs[randomImg], // 随机图标
|
||||
|
|
@ -111,22 +187,24 @@
|
|||
x: Math.ceil(Math.random() * this.propRange), // 方向间距
|
||||
q: Math.floor(Math.random() * 2), // 随机方向
|
||||
}
|
||||
// 动画
|
||||
// 计算随机飞行方向和距离
|
||||
let _abs = ['-', '']
|
||||
let _dirX = Number(_abs[_item.q] + _item.x) // 随机的方向和间距
|
||||
let _dirY = this.propHigh - Math.random() * 10
|
||||
// 生成DOM
|
||||
// 添加到渲染列表
|
||||
this.elId++
|
||||
this.viewList.push(_item)
|
||||
// #ifndef APP-NVUE
|
||||
// 非NVUE环境下创建动画实例
|
||||
_item.animation = uni.createAnimation({
|
||||
duration: this.propDuration,
|
||||
timingFunction: 'ease-out',
|
||||
})
|
||||
// 设置动画结束后的处理逻辑
|
||||
setTimeout(() => {
|
||||
// 完成后事件回调
|
||||
this.$emit('finished')
|
||||
// 逐渐消失
|
||||
// 根据propAlone属性决定逐个删除还是一起删除
|
||||
if (this.propAlone) {
|
||||
this.waitDeleteIndex++
|
||||
this.onThrottle(this.deleteView, this.propDuration)
|
||||
|
|
@ -144,13 +222,16 @@
|
|||
// 执行动画
|
||||
setTimeout(() => {
|
||||
this.$nextTick(() => {
|
||||
// 确定缩放倍数
|
||||
let _n = 1
|
||||
if (this.propLarge) _n = typeof(this.propLarge) === 'number' ? this.propLarge : 2;
|
||||
// #ifndef APP-NVUE
|
||||
// 非NVUE环境下的动画实现
|
||||
_item.animation.translateY(-_dirY).translateX(_dirX).scale(_n, _n).opacity(0).step()
|
||||
_item.animation = _item.animation.export()
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
// NVUE环境下的动画实现
|
||||
let el = this.$refs[_item.elId][0];
|
||||
clearTimeout(this.timer)
|
||||
_item.animation.transition(el, {
|
||||
|
|
@ -166,7 +247,7 @@
|
|||
console.log('animation finished.')
|
||||
// 完成后事件回调
|
||||
this.$emit('finished')
|
||||
// 逐渐消失
|
||||
// 根据propAlone属性决定逐个删除还是一起删除
|
||||
if (this.propAlone) {
|
||||
this.waitDeleteIndex++
|
||||
this.onThrottle(this.deleteView, this.propDuration)
|
||||
|
|
@ -185,10 +266,18 @@
|
|||
// 点击立即触发组件事件
|
||||
this.$emit('handleClick', this.elId)
|
||||
},
|
||||
/**
|
||||
* 删除已完成动画的视图元素
|
||||
*/
|
||||
deleteView() {
|
||||
this.viewList.splice(0, this.waitDeleteIndex)
|
||||
this.waitDeleteIndex = 0
|
||||
},
|
||||
/**
|
||||
* 节流函数,控制函数执行频率
|
||||
* @param {Function} fn 需要节流的函数
|
||||
* @param {Number} delay 延迟时间(毫秒)
|
||||
*/
|
||||
onThrottle(fn, delay) {
|
||||
let verifi = true
|
||||
return (function() {
|
||||
|
|
@ -205,6 +294,7 @@
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 动画元素固定定位样式 */
|
||||
.a-img {
|
||||
position: fixed;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,20 @@
|
|||
},
|
||||
|
||||
methods: {
|
||||
// 初始配置
|
||||
/**
|
||||
* 初始化分享配置
|
||||
* @param {Object} config - 配置参数
|
||||
* @param {String} config.type - 分享类型
|
||||
* @param {Number} config.is_goods_poster - 是否为商品海报分享 (0|1)
|
||||
* @param {Number} config.goods_id - 商品ID
|
||||
* @param {String} config.url - 分享链接
|
||||
* @param {String} config.images - 分享图片
|
||||
* @param {String} config.title - 分享标题
|
||||
* @param {String} config.summary - 分享摘要
|
||||
* @param {Object} config.share_info - 分享信息
|
||||
* @param {Boolean} config.status - 是否显示分享弹窗
|
||||
* @returns {Boolean} 初始化结果
|
||||
*/
|
||||
init(config = {}) {
|
||||
if (!app.globalData.is_single_page_check()) {
|
||||
return false;
|
||||
|
|
@ -168,12 +181,16 @@
|
|||
// #endif
|
||||
},
|
||||
|
||||
// 弹层关闭
|
||||
/**
|
||||
* 关闭分享弹窗
|
||||
*/
|
||||
popup_close_event(e) {
|
||||
this.$refs.popupShareRef.close();
|
||||
},
|
||||
|
||||
// url链接地址复制分享
|
||||
/**
|
||||
* 复制链接分享
|
||||
*/
|
||||
share_url_copy_event() {
|
||||
var url = app.globalData.get_page_url();
|
||||
// 增加分享标识
|
||||
|
|
@ -187,7 +204,9 @@
|
|||
app.globalData.text_copy_event(url);
|
||||
},
|
||||
|
||||
// 基础分享事件
|
||||
/**
|
||||
* 基础分享事件(支付宝小程序)
|
||||
*/
|
||||
share_base_event() {
|
||||
this.$refs.popupShareRef.close();
|
||||
uni.pageScrollTo({
|
||||
|
|
@ -201,7 +220,9 @@
|
|||
});
|
||||
},
|
||||
|
||||
// 商品海报分享
|
||||
/**
|
||||
* 商品海报分享
|
||||
*/
|
||||
poster_event() {
|
||||
var user = app.globalData.get_user_info(this, 'poster_event');
|
||||
if (user != false) {
|
||||
|
|
@ -235,7 +256,13 @@
|
|||
}
|
||||
},
|
||||
|
||||
// app分享
|
||||
/**
|
||||
* APP端分享事件
|
||||
* @param {Object} e - 事件对象
|
||||
* @param {Object} e.currentTarget.dataset - 事件数据集
|
||||
* @param {String} e.currentTarget.dataset.provider - 分享提供商(如:weixin、qq)
|
||||
* @param {String} e.currentTarget.dataset.scene - 分享场景(如:WXSceneSession、WXSceneTimeline等)
|
||||
*/
|
||||
share_app_event(e) {
|
||||
// 分享参数
|
||||
var provider = e.currentTarget.dataset.provider;
|
||||
|
|
|
|||
|
|
@ -13,11 +13,22 @@
|
|||
<script>
|
||||
import H5HlsVideo from '@/pages/plugins/live/pull/components/h5-hls-video/h5-hls-video.vue';
|
||||
import { isEmpty } from '@/common/js/common/common.js';
|
||||
|
||||
/**
|
||||
* 直播拉流视频组件
|
||||
* 支持H5、小程序和APP三种平台的视频播放
|
||||
* 根据不同平台使用不同的播放器组件实现视频播放功能
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
H5HlsVideo
|
||||
},
|
||||
props: {
|
||||
/**
|
||||
* 视频源地址
|
||||
* @type {String}
|
||||
* @default 'http://live-pull-all.shopxo.vip/68f764013572f9240ca7ce6c/shopxo122.m3u8'
|
||||
*/
|
||||
propSrc:{
|
||||
type: String,
|
||||
default: 'http://live-pull-all.shopxo.vip/68f764013572f9240ca7ce6c/shopxo122.m3u8'
|
||||
|
|
@ -31,14 +42,25 @@
|
|||
}
|
||||
},
|
||||
created() {
|
||||
// 获取窗口信息,用于设置视频尺寸
|
||||
const data = uni.getWindowInfo();
|
||||
this.windowWidth = data.windowWidth;
|
||||
this.windowHeight = data.windowHeight;
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 直播播放器状态变化处理函数(小程序平台)
|
||||
* @param {Object} e - 状态变化事件对象
|
||||
*/
|
||||
statechange(e) {
|
||||
console.log(e.detail.code);
|
||||
},
|
||||
|
||||
/**
|
||||
* 播放错误处理函数
|
||||
* 根据不同平台处理播放错误,并在适当条件下触发ended事件
|
||||
* @param {Object} e - 错误事件对象
|
||||
*/
|
||||
error(e) {
|
||||
// #ifdef H5
|
||||
// 非初次加载错误的, 直播结束
|
||||
|
|
@ -53,11 +75,22 @@
|
|||
// #endif
|
||||
console.log(e, 'error');
|
||||
},
|
||||
|
||||
/**
|
||||
* 视频播放结束处理函数
|
||||
* 当视频播放完成时触发ended事件通知父组件
|
||||
*/
|
||||
// video app使用这种方式,判断直播是否结束
|
||||
ended() {
|
||||
this.$emit('ended');
|
||||
},
|
||||
|
||||
//#ifdef H5
|
||||
/**
|
||||
* H5平台自动播放成功处理函数
|
||||
* 当静音自动播放成功时触发mutedAutoPlaySuccess事件
|
||||
* @param {Boolean} e - 是否自动播放成功
|
||||
*/
|
||||
// 网页有的时候直接访问会报错,所以这里需要判断一下,如果报错则静音播放,静音播放成功添加提示,用户操作之后改为非静音播放
|
||||
// 静音自动播放成功, 触发事件, 添加提示弹出框,用户操作之后改为非静音播放
|
||||
auto_play_success(e) {
|
||||
|
|
@ -66,6 +99,12 @@
|
|||
this.$emit('mutedAutoPlaySuccess');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* H5平台自动播放失败处理函数
|
||||
* 当自动播放失败时,设置为静音状态重新尝试播放
|
||||
* @param {Boolean} e - 是否自动播放失败
|
||||
*/
|
||||
// 自动播放失败, 静音播放
|
||||
auto_play_error(e) {
|
||||
// 播放失败,并且是非静音状态,则静音播放尝试是否成功
|
||||
|
|
@ -73,6 +112,11 @@
|
|||
this.muted = true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* H5平台静音状态切换函数
|
||||
* 用户点击后取消静音状态
|
||||
*/
|
||||
// 静音提示点击
|
||||
muted_tap() {
|
||||
this.muted = false;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
/**
|
||||
* 直播间混入组件
|
||||
* 提供直播间相关的基本功能和数据管理
|
||||
*/
|
||||
const app = getApp();
|
||||
import { isEmpty } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
/**
|
||||
* 组件内部数据
|
||||
*/
|
||||
data() {
|
||||
return {
|
||||
windowWidth: 0,
|
||||
|
|
@ -20,6 +27,11 @@ export default {
|
|||
lastLikeTime: 0 // 记录上次点赞时间,用于防抖
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面加载时执行
|
||||
* @param {Object} params 页面参数
|
||||
*/
|
||||
onLoad(params) {
|
||||
// 调用公共事件方法
|
||||
app.globalData.page_event_onload_handle(params);
|
||||
|
|
@ -27,6 +39,9 @@ export default {
|
|||
this.params = app.globalData.launch_params_handle(params);
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面显示时执行
|
||||
*/
|
||||
onShow() {
|
||||
// 调用公共事件方法
|
||||
app.globalData.page_event_onshow_handle();
|
||||
|
|
@ -41,10 +56,19 @@ export default {
|
|||
// #endif
|
||||
this.init();
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件挂载完成后执行
|
||||
*/
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 初始化直播间数据
|
||||
* 请求服务器获取直播间详情信息
|
||||
*/
|
||||
init() {
|
||||
uni.showLoading({
|
||||
title: '直播数据加载中...',
|
||||
|
|
@ -88,13 +112,25 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 标记直播结束
|
||||
*/
|
||||
ended() {
|
||||
this.is_live_ended = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回上一页
|
||||
*/
|
||||
live_back() {
|
||||
app.globalData.page_back_prev_event();
|
||||
},
|
||||
// 处理鼠标双击事件
|
||||
|
||||
/**
|
||||
* 处理鼠标双击事件
|
||||
* @param {Event} event 鼠标事件对象
|
||||
*/
|
||||
handle_double_click(event) {
|
||||
if (event.target.dataset.ignore) {
|
||||
return;
|
||||
|
|
@ -116,7 +152,11 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
// 处理触屏双击事件
|
||||
/**
|
||||
* 处理触屏双击事件
|
||||
* 检测用户在屏幕上的双击操作以触发点赞效果
|
||||
* @param {Event} event 触摸事件对象
|
||||
*/
|
||||
handle_touch_end(event) {
|
||||
if (event.target.dataset.ignore) {
|
||||
return;
|
||||
|
|
|
|||
Loading…
Reference in New Issue