如何灵活实现文本或图片的展开收起功能?

实现这样一个需求:有一个商品详情页需要展示商品描述内容,内容有三种情况,纯文本,纯图片,文本加图片,展示区域有一个固定高度,如果内容超过这个高度则显示展开按钮,点击展开按钮可展开更多内容;如果内容没有超过这个高度则不显示展开按钮

实现思路:
首先要根据内容的高度是否超过指定高度来判断展开按钮显示与否,所以需要先获取dom元素,以及元素的高度,由于页面渲染需要时间,所以在获取元素高度这里需要加一个延时;然后因为图片渲染的时间要比文本更长,尤其是有很多张图片的情况下,所以在判断内容有图片的情况下,需要在图片的onload事件里执行获取元素的高度,也就是在图片渲染完成以后再去获取元素的高度;由于加了延时以后,图片会有一个先展开了全部然后突然被收起的动作,用户体验很不好,所以在这里加了一个骨架屏起到一个隐藏渲染过程的效果

具体代码如下:

父组件:

<template>
	<div class="merchant-wrap">
		<div v-if="isShowSkeleton>
			"5" round>
			<van-skeleton :row="5" round>
			<van-skeleton :row="5" round>
		div>
		<div class="merchant-reminds" v-if="!isShowSkeleton">
		<div class="merchant-reminds-wrap">
			<div class="reminds-header" id="tabs0">
				<goods :data="data.detailsInfo" :isDetail="true" >
			div>
		div>
	div>
template>
import {ref,reactive} from 'vue'
import Goods from './components/goods . vue'
import { goodsDetail ] from '@/api/modules/good.js'

export default {
	setup(){
		const isShowSkeleton = ref(true)
		const data = reactive({
			detailsInfo:{}
		})
		const getGoodsDetall = () => {
			isShowSkeleton .value = true
			goodsDetail({ goodsId: route.query.goodsId })
			then(res => {
				if (res) {
					if (res .code == 20000) {
						isShowSkeleton.value = false
						data.detailsInfo = res.data.goods
					}
				}
			})
			.catch(error => {})
		}
		const init = () => {
			getGoodsDetall()
		}
		init()
		return {
			isShowSkeleton
		}
	},
	components: {
		Goods
	}
}	

子组件

<template>
	<div v-if="isShowMask>
		"5" round>
		<van-skeleton :row="5" round>
		<van-skeleton :row="5" round>
	div>
	<div class="content">
		<div class="goods-picture" v-if="data.des">
			<div :class="[state.isRulesshow ? 'img-detail':'img-content']" class="goods-picture-content">
				<div class="content-wrap" v-for="(item, index) in data.des" :key="index">
					// 渲染文本
					<div>
						<div class="item-text" v-if="item.type == 0" v-html="item.value">div>
					div>
					// 渲染图片
					<div v-if="item.type == 1 && item.value">
						<div v-for="(ele, index) in item.value.split(",")" :key="index">
							<img @load="loadImage” :src="ele" alt="" />				
						div>
					div>
				div>
			div>
		div>
		<div v-if="isShowMore" class="look-all" @click="switchRules">
			<div class="rules-words">{{ rulesWords }}div>
			<div class="arrow_down">
				<img class="arrow" src="@/assets/iconsvg/arrowDown.svg" :class="{ active:state.isRulesshow}" alt="" />
			div>
		div>
	div>
template>
import {ref,reactive,computed,nextTick} from 'vue'

export default {
	props: {
		data: {
			type: Object,
			default: () => ({}),
		}
	},
	setup(props){
		const isShowMask = ref(true)
		const isShowMore = ref(false)
		const state = reactive({
			isRule:{}
		})
		const loadImage = () => {
			console.log('图片加载完成')
			getTextHeight()
		}
		const getTextHeight = () => {
			console.log(11111)
			const contentDiv = document.querySelectorAl1('.content-wrap')
			let divHeight = 0
			if (contentDiv && contentDiv.length > 0){
				contentDiv.forEach(item => {
					divHeight += item.offsetHeight
				})
				console.log(divHeight,---- --- ---divHeight")
				if (divHeight > 150) {
					isShowMore.value = true
					setTimeout(() => {
						isShowMask.value = false
					},500)
				} else {
					isShowMask.value = false
				}
			} else {
				isShowMask.value = false
			}
		},
		const init = () => {
			if (props .data .des ) {
				let imgData = props.data.des.filter(item => {
					return item.type == '1'
				})
				let textData = props.data.des.filter(item => {
					return item.type == '0'
				})
				if (imgData.length || textData.length > 0) {
					if (imgData.length > 0) {
						loadImage()
					} else {
						setTimeout(() => {
							getTextHeight()
						}400)
					}
				} else {
					isShowMask.value = false
				}
			} else 
				isShowMask.value = false
			}
		}const rulesWords = computed(()
			if (state.isRulesShow === false) {
				return lang.value == '更多'
			} else if (state.isRulesShow === true) {
				return lang.value == '收起'
			} else if (state.isRulesshow === '') {
				return null
			} else {
				return null
			}
		})
		const switchRules = () => (
			state.isRuleShow = !state.isRulesShow
		}	
		onMounted(() => {
			nextTick(() => {
				init()
			})
		})
		return {
			isShowMask,
			isShowMore,
			rulesWords,
			switchRules
		}
	},
}	

你可能感兴趣的:(javascript,前端,vue.js)