| 
						 | 
						- /**
 -  * 可见性监听混入
 -  * 提供元素可见性监听功能,支持H5、微信小程序、App端
 -  * 用于实现浏览记录等功能
 -  */
 - import { VIEWPORT_CONFIG, createBrowseRecordParams } from '@/config/browseConfig.js'
 - 
 - export default {
 - 	data() {
 - 		return {
 - 			hasRecordedView: false, // 标记是否已记录浏览
 - 			viewTimer: null, // 浏览计时器
 - 			isInViewport: false, // 是否在可视区域内
 - 			observer: null, // 观察者实例
 - 		}
 - 	},
 - 	
 - 	mounted() {
 - 		// 组件挂载后,使用Intersection Observer监听可见性
 - 		this.observeVisibility()
 - 	},
 - 	
 - 	beforeDestroy() {
 - 		// 组件销毁前清理observer和计时器
 - 		this.cleanupObserver()
 - 	},
 - 	
 - 	methods: {
 - 		/**
 - 		 * 监听元素可见性
 - 		 * @param {String} selector - 要监听的元素选择器,默认为'.works'
 - 		 * @param {Object} config - 配置参数
 - 		 */
 - 		observeVisibility(selector = '.works', config = {}) {
 - 			const {
 - 				threshold = VIEWPORT_CONFIG.THRESHOLD,
 - 				dwellTime = VIEWPORT_CONFIG.DWELL_TIME,
 - 				margins = VIEWPORT_CONFIG.VIEWPORT_MARGINS
 - 			} = config
 - 			
 - 			// #ifdef H5
 - 			if (typeof IntersectionObserver !== 'undefined') {
 - 				this.observer = new IntersectionObserver((entries) => {
 - 					entries.forEach(entry => {
 - 						if (entry.isIntersecting && !this.hasRecordedView) {
 - 							// 元素进入可视区域且未记录过浏览
 - 							this.handleViewportEnter(dwellTime)
 - 						} else if (!entry.isIntersecting && this.isInViewport) {
 - 							// 元素离开可视区域
 - 							this.handleViewportLeave()
 - 						}
 - 					})
 - 				}, {
 - 					threshold: threshold
 - 				})
 - 				
 - 				this.observer.observe(this.$el)
 - 			} else {
 - 				// 降级方案:延迟记录浏览
 - 				setTimeout(() => {
 - 					if (!this.hasRecordedView) {
 - 						this.recordBrowseView()
 - 					}
 - 				}, dwellTime)
 - 			}
 - 			// #endif
 - 			
 - 			// #ifdef MP-WEIXIN
 - 			// 使用微信小程序原生的IntersectionObserver API
 - 			this.observer = wx.createIntersectionObserver(this, {
 - 				thresholds: [threshold],
 - 				initialRatio: 0,
 - 				observeAll: false
 - 			})
 - 			
 - 			// 指定页面显示区域作为参照区域
 - 			this.observer.relativeToViewport(margins)
 - 			
 - 			// 开始监听目标节点
 - 			this.observer.observe(selector, (res) => {
 - 				if (res.intersectionRatio > threshold && !this.hasRecordedView) {
 - 					// 当元素达到配置阈值以上进入可视区域且未记录过浏览时,处理进入可视区域事件
 - 					this.handleViewportEnter(dwellTime)
 - 				} else if (res.intersectionRatio <= threshold && this.isInViewport) {
 - 					// 元素离开可视区域
 - 					this.handleViewportLeave()
 - 				}
 - 			})
 - 			// #endif
 - 			
 - 			// #ifdef APP-PLUS
 - 			// App端使用uni-app的createIntersectionObserver
 - 			this.observer = uni.createIntersectionObserver(this, {
 - 				thresholds: [threshold],
 - 				initialRatio: 0,
 - 				observeAll: false
 - 			})
 - 			
 - 			this.observer.relativeToViewport(margins)
 - 			
 - 			this.observer.observe(selector, (res) => {
 - 				if (res.intersectionRatio > threshold && !this.hasRecordedView) {
 - 					this.handleViewportEnter(dwellTime)
 - 				} else if (res.intersectionRatio <= threshold && this.isInViewport) {
 - 					this.handleViewportLeave()
 - 				}
 - 			})
 - 			// #endif
 - 		},
 - 		
 - 		/**
 - 		 * 处理进入可视区域事件
 - 		 * @param {Number} dwellTime - 停留时间
 - 		 */
 - 		handleViewportEnter(dwellTime = VIEWPORT_CONFIG.DWELL_TIME) {
 - 			if (this.hasRecordedView) return
 - 			
 - 			this.isInViewport = true
 - 			
 - 			// 设置延迟计时器,确保用户真正浏览了内容
 - 			this.viewTimer = setTimeout(() => {
 - 				if (this.isInViewport && !this.hasRecordedView) {
 - 					this.recordBrowseView()
 - 				}
 - 			}, dwellTime)
 - 		},
 - 		
 - 		/**
 - 		 * 处理离开可视区域事件
 - 		 */
 - 		handleViewportLeave() {
 - 			this.isInViewport = false
 - 			
 - 			// 清除计时器,如果用户快速滚动过去,不记录浏览
 - 			if (this.viewTimer) {
 - 				clearTimeout(this.viewTimer)
 - 				this.viewTimer = null
 - 			}
 - 		},
 - 		
 - 		/**
 - 		 * 记录浏览行为
 - 		 * @param {String} itemType - 项目类型,默认为'dynamic'
 - 		 * @param {String} itemId - 项目ID,默认从this.item.id获取
 - 		 */
 - 		recordBrowseView(itemType = 'dynamic', itemId = null) {
 - 			const id = itemId || (this.item && this.item.id)
 - 			
 - 			if (this.hasRecordedView || !id) return
 - 			
 - 			this.hasRecordedView = true
 - 			
 - 			// 清除计时器
 - 			if (this.viewTimer) {
 - 				clearTimeout(this.viewTimer)
 - 				this.viewTimer = null
 - 			}
 - 			
 - 			// 使用配置文件中的参数创建API请求参数
 - 			const params = createBrowseRecordParams(id, itemType)
 - 			
 - 			// 调用浏览记录API
 - 			this.$api('addBrowseRecord', params, res => {
 - 				if (res.code === 200) {
 - 					console.log('浏览记录已保存:', id)
 - 				}
 - 			})
 - 		},
 - 		
 - 		/**
 - 		 * 清理观察者和计时器
 - 		 */
 - 		cleanupObserver() {
 - 			if (this.observer) {
 - 				// #ifdef H5
 - 				if (typeof this.observer.disconnect === 'function') {
 - 					this.observer.disconnect()
 - 				}
 - 				// #endif
 - 				
 - 				// #ifdef MP-WEIXIN || APP-PLUS
 - 				if (typeof this.observer.disconnect === 'function') {
 - 					this.observer.disconnect()
 - 				}
 - 				// #endif
 - 				
 - 				this.observer = null
 - 			}
 - 			
 - 			if (this.viewTimer) {
 - 				clearTimeout(this.viewTimer)
 - 				this.viewTimer = null
 - 			}
 - 		},
 - 		
 - 		/**
 - 		 * 重置浏览记录状态
 - 		 */
 - 		resetBrowseRecord() {
 - 			this.hasRecordedView = false
 - 			this.isInViewport = false
 - 			this.cleanupObserver()
 - 		}
 - 	}
 - }
 
 
  |