uni-app 小说滑动阅读功能实现

时间:2025-01-28 08:42:58

小说项目增添了内容左右滑动需求,于是用了 uni-app 内置的 swiper 来做左右滑动

HTML代码:

	<view 
	class="content-text" 
	id="box" 
	:style="{fontSize: fontSize + 'px'}" 
	v-if="topRight"
	>
		<view id="data">
		  <rich-text :nodes="contentData"></rich-text>
		</view>
	</view>
	
	<swiper  
	v-if="topRight"
	:style="{ backgroundColor: novelBgStyle, color: novelColor,fontSize: fontSize + 'px' }" 
	class="swiper1" 
	:duration="500"
	:current = "swiper_index"
	@animationfinish = 'swiperChange'
	>
		<swiper-item 
		v-for="(item,index) in sliderContent" :key='index' 
		:item-id=""
		>
			<view class="swiper-item" v-html=""></view>
		</swiper-item>
	</swiper>

原本是用 v-show 显示隐藏,后来发现时好时坏,于是改用 v-if 。
最上面的 view 盒子是用来测量内容高度的,外面还有一个父盒子是视窗高度,层级显示在最后面。



1.数据填充进第一个盒子后获取内容高度

uni.request({
	url: this.urls + '/app/bookDetail/content?ids=' + send_id,
	success: res => {
		let swiper_title_init = `<h3 style="margin-bottom:20px">${res.data.data[0].title}</h3>`;
		this.contentData = swiper_title_init + res.data.data[0].content;

		var box = uni.createSelectorQuery().select('#box');		//获取父盒子高度
		box.boundingClientRect(data => {
			this.boxHeight = Math.floor(data.height / 26) * 26;
			
			setTimeout(()=>{	// setTimeout后才能获取到填充了内容的盒子高度
				var text = uni.createSelectorQuery().select('#data');	//获取内容高度
				text.fields({size:true} , data => {
					this.textHeight = data.height;
					let len = Math.ceil(this.textHeight/this.boxHeight);	//	内容分成len个视窗(父盒子)的高度
					// 每个视窗含有的字符个数
					let throat = Math.ceil((this.boxHeight/this.textHeight)*this.contentData.length);
					for (let i = 0; i < len ; i++){
						this.countText(throat,i,send_id);
					}
					if(callback){
						callback();
					}
				}).exec();
			})
		}).exec()
	}
});


2.根据获取的高度裁剪内容后填充

countText(throat,index,id){
	let tempstr = '';
	let arr = '';
	let str = this.contentData.charAt(throat);
	let id_and_index = id+'-'+index;
	let put_data = {};
	// 判断截取部分是否是<p></p>标签和<br/>标签 具体自己编写~我的代码还没精简 就发个简单版的
	if(str == '<') {
		if(this.contentData.charAt(throat+2) == '>'){
			tempstr = this.contentData.slice(0, throat+3);
			arr = this.contentData.split("");
			arr.splice(0, throat+3);
		}
	}
	this.contentData = arr.join("");	// 截取后删掉原数据被截取部分
	put_data.text = tempstr;
	put_data.id = id_and_index;			//这里下面说明
	this.sliderContent.push(put_data);
}

放入id和index 是这一章内容的id 和 这一章分页截取后的页数,后面会放到 swiper-item 的 item-id 属性当中(:item-id=“”) 就可以在 swiper @change 或者 @animationfinish 的调用中 取到 到时候方便调用记录和返回历史;
推荐用 @animationfinish 监听加载更多,这样看起来不会卡顿。

基本的滑动功能 这里就说完了!



补个坑点:

H5端测试没问题 手机端滑动后 更换章节时 swiper会卡死 数据什么的获取填充都是正常的 但是显示正常,
这时候用 v-if 的好处就出来了

this.topRight = false;		//v-if 
this.sliderContent = [];
setTimeout(()=>{
	this.topRight = true;	//v-if 
	this.sliderPage(id);
})

先用 v-if 销毁 DOM 然后重新创建渲染 必须用 setTimeout 打个时间差,不然不管用,实测!!!这问题找了好久,才找出来。