<template>
    <view class="zh-readMore">
        <view class="zh-readMore-wrapper" :style="[textStyle]">
            <view
                class="zh-text"
                :class="textClass"
                :style="[textStyleObject, { '--unfold_packup_line': `${unfold_packup_line}px` }, { '--duration': `${duration}s` }]"
            >
                <view class="zh-open" :style="[unfoldTextStyle]" v-if="!showall && is_open" @click.stop="open">
                    <text class="zh-ellipsis">...</text>
                    <text class="zh-open-text">{{ unfoldText }}</text>
                </view>
                <text class="" :style="[lineBreakStyles]">
                    <text v-if="title" :style="[titleStyle]">{{ title }}</text>
                    {{ text }}
                </text>
                <text class="zh-fewer" v-if="is_open && showall" @click.stop="open">
                    <text class="zh-fewer-text" :style="[packupTextStyle]">{{ packupText }}</text>
                </text>
            </view>
        </view>
        <view class="zh-overflowcont" id="zh-overflowcont" :style="[textStyle, lineStyle]">
            <text class="zh-overflowcont-text" :style="[lineBreakStyle]">
                <text v-if="title" :style="[titleStyle]">{{ title }}</text>
                {{ text }}
            </text>
        </view>
        <view class="zh-overflowcont" id="zh-overflowcontline" :style="[textStyle]">
            <text class="" :style="[lineBreakStyle]">{{ text }}</text>
        </view>
        <view class="zh-overflowcont">
            <view class="" :style="[unfoldTextStyle]" id="zh-open">
                <text class="zh-ellipsis">...</text>
                <text class="zh-overflowcont-open">{{ unfoldText }}</text>
            </view>
        </view>
    </view>
</template>

<!-- #ifdef VUE3 -->
<!-- vue3 -->
<script lang="ts" setup>
    /*
     * @param {text,String} 需要展示的文本
     * @param {textStyle,Object} 需要展示的文本样式
     * @param {rows,Number} 文本容器中超出多行后显示省略号
     * @param {lineBreak,Boolean} 保留空白字符序列，同时允许正常换行
     * @param {packupLineBreak,Boolean} 只在收起时，忽略空白字符；展开时，保留空白字符序列，同时允许正常换行
     * @param {unfoldText,String} 展开操作的文案
     * @param {unfoldTextStyle,Object} 展开操作的样式
     * @param {packupText,String} 收起操作的文案
     * @param {packupTextStyle,Object} 收起操作的样式
     * @param {duration,Number || String} 展示动画过度时间(单位s)
     */
    import { computed, nextTick, ref, watch, getCurrentInstance } from 'vue'
    const props = defineProps({
        title: {
            type: String,
            default: () => '',
        },
        titleStyle: {
            type: Object,
            default: () => ({
                'font-weight': '600',
                'margin-right': '10rpx',
            }),
        },
        text: {
            type: String,
            default: () => '',
        },
        textStyle: {
            type: Object,
            default: () => ({
                color: '#000',
                'font-size': '28rpx',
                'font-weight': '400',
            }),
        },
        rows: {
            type: Number,
            default: 3,
        },
        lineBreak: {
            type: Boolean,
            default: true,
        },
        packupLineBreak: {
            type: Boolean,
            default: false,
        },
        unfoldText: {
            type: String,
            default: () => '展开',
        },
        unfoldTextStyle: {
            type: Object,
            default: () => ({
                color: '#206ef7',
                'font-size': '28rpx',
                'font-weight': '400',
            }),
        },
        packupText: {
            type: String,
            default: () => '收起',
        },
        packupTextStyle: {
            type: Object,
            default: () => ({
                color: '#206ef7',
                'font-size': '28rpx',
                'font-weight': '400',
            }),
        },
        duration: {
            type: [Number, String],
            default: () => 0,
        },
    })

    const box_h = ref(0) //展开后的高度
    const showall = ref(false) //是否展开
    const is_open = ref(false) //是否显示展开/收起按钮
    const unfold_packup_line = ref(22) //展开收起宽度
    const settime = ref(null) //定时器标识

    const instance = getCurrentInstance()
    const selectQuery = uni.createSelectorQuery().in(instance.proxy)

    //导出自定义事件
    const emit = defineEmits(['click'])

    //事件
    //展开收起事件
    const open = () => {
        showall.value = !showall.value
        emit('click', showall.value) //展开true 关闭false
    }

    //计算属性

    const textStyleObject = computed(() => {
        const { rows } = props
        return {
            'max-height': showall.value ? `${1.5 * box_h.value}em` : `${1.5 * rows}em`,
        }
    })

    const textClass = computed(() => {
        return showall.value ? 'showall' : ''
    })

    const lineStyle = computed(() => {
        const { rows } = props
        return {
            display: '-webkit-box',
            '-webkit-box-orient': 'vertical',
            '-webkit-line-clamp': rows,
            overflow: 'hidden',
            'word-break': 'break-all',
        }
    })

    const lineBreakStyles = computed(() => {
        const { lineBreak, packupLineBreak } = props
        if (!lineBreak) {
            return {
                'white-space': 'normal',
            }
        } else {
            if (packupLineBreak) {
                return {
                    'white-space': showall.value ? 'pre-wrap' : 'normal',
                }
            } else {
                return {
                    'white-space': 'pre-wrap',
                }
            }
        }
    })

    const lineBreakStyle = computed(() => {
        const { lineBreak } = props
        return {
            'white-space': lineBreak ? 'pre-wrap' : 'normal',
        }
    })

    // 监听
    watch(
        () => props.text,
        (newValue, oldValue) => {
            const { rows } = props
            nextTick(() => {
                clearTimeout(settime.value)
                settime.value = setTimeout(() => {
                    selectQuery.select(`#zh-overflowcont`).boundingClientRect()
                    selectQuery.select('#zh-overflowcontline').boundingClientRect()
                    selectQuery.select('#zh-open').boundingClientRect()
                    selectQuery.exec(res => {
                        if (res && res[0] && res[1]) {
                            const h1 = res[0].height // 收起时高度
                            const h2 = res[1].height // 展开时高度
                            const lineCount = rows
                            const lineHeight = h1 / lineCount

                            // 计算实际行数（考虑空行）
                            const actualLines = Math.ceil(h2 / lineHeight)

                            // 如果实际行数超过限制行数，或者高度差超过0.1行，才显示展开/收起按钮
                            if (actualLines > lineCount || h2 > h1 + lineHeight * 0.1) {
                                is_open.value = true
                            } else {
                                is_open.value = false
                            }
                            box_h.value = Math.ceil(h2 / lineHeight) + 1
                            showall.value = false
                        }
                        if (res && res[2]) {
                            let unfold_packup_width = res[2].height - 1.5 || 22
                            unfold_packup_line.value = unfold_packup_width
                        }
                    })
                }, 100)
            })
        },
        {
            deep: true,
            immediate: true,
        }
    )
</script>

<!-- #endif -->

<!-- #ifdef VUE2 -->
<!-- vue2 -->

<script>
    /*
     * @param {text,String} 需要展示的文本
     * @param {textStyle,Object} 需要展示的文本样式
     * @param {rows,Number} 文本容器中超出多行后显示省略号
     * @param {lineBreak,Boolean} 保留空白字符序列，同时允许正常换行
     * @param {packupLineBreak,Boolean} 只在收起时，忽略空白字符；展开时，保留空白字符序列，同时允许正常换行
     * @param {unfoldText,String} 展开操作的文案
     * @param {unfoldTextStyle,Object} 展开操作的样式
     * @param {packupText,String} 收起操作的文案
     * @param {packupTextStyle,Object} 收起操作的样式
     * @param {duration,Number || String} 展示动画过度时间(单位s)
     */

    export default {
        name: 'zh-readMore',
        props: {
            title: {
                type: String,
                default: () => '',
            },
            titleStyle: {
                type: Object,
                default: () => ({
                    'font-weight': '600',
                    'margin-right': '10rpx',
                }),
            },
            text: {
                type: String,
                default: () => '',
            },
            textStyle: {
                type: Object,
                default: () => ({
                    color: '#000',
                    'font-size': '28rpx',
                    'font-weight': '400',
                }),
            },
            rows: {
                type: Number,
                default: 3,
            },
            lineBreak: {
                type: Boolean,
                default: true,
            },
            packupLineBreak: {
                type: Boolean,
                default: false,
            },
            unfoldText: {
                type: String,
                default: () => '展开',
            },
            unfoldTextStyle: {
                type: Object,
                default: () => ({
                    color: '#206ef7',
                    'font-size': '28rpx',
                    'font-weight': '400',
                }),
            },
            packupText: {
                type: String,
                default: () => '收起',
            },
            packupTextStyle: {
                type: Object,
                default: () => ({
                    color: '#206ef7',
                    'font-size': '28rpx',
                    'font-weight': '400',
                }),
            },
            duration: {
                type: Number || String,
                default: () => 0,
            },
        },
        data() {
            return {
                box_h: 0, //展开后的高度
                showall: false, //是否展开
                is_open: false, //是否显示展开/收起按钮
                unfold_packup_line: 22, //展开收起宽度
                settime: null, //定时器标识
            }
        },
        methods: {
            //展开收起事件
            open() {
                this.showall = !this.showall
                this.$emit('click', this.showall) //展开true 关闭false
            },
        },
        mounted() {},
        computed: {
            textStyleObject() {
                return {
                    'max-height': this.showall ? `${1.5 * this.box_h}em` : `${1.5 * this.rows}em`,
                }
            },
            textClass() {
                return this.showall ? 'showall' : ''
            },
            lineStyle() {
                return {
                    display: '-webkit-box',
                    '-webkit-box-orient': 'vertical',
                    '-webkit-line-clamp': this.rows,
                    overflow: 'hidden',
                    'word-break': 'break-all',
                }
            },
            lineBreakStyles() {
                if (!this.lineBreak) {
                    return {
                        'white-space': 'normal',
                    }
                } else {
                    if (this.packupLineBreak) {
                        return {
                            'white-space': this.showall ? 'pre-wrap' : 'normal',
                        }
                    } else {
                        return {
                            'white-space': 'pre-wrap',
                        }
                    }
                }
            },
            lineBreakStyle() {
                return {
                    'white-space': this.lineBreak ? 'pre-wrap' : 'normal',
                }
            },
        },
        watch: {
            text: {
                handler(newValue, oldValue) {
                    this.$nextTick(() => {
                        clearTimeout(this.settime)
                        this.settime = setTimeout(() => {
                            const selectQuery = uni.createSelectorQuery().in(this)
                            selectQuery.select(`#zh-overflowcont`).boundingClientRect()
                            selectQuery.select('#zh-overflowcontline').boundingClientRect()
                            selectQuery.select('#zh-open').boundingClientRect()
                            selectQuery.exec(res => {
                                if (res && res[0] && res[1]) {
                                    const h1 = res[0].height // 收起时高度
                                    const h2 = res[1].height // 展开时高度
                                    const lineCount = this.rows
                                    const lineHeight = h1 / lineCount

                                    // 计算实际行数（考虑空行）
                                    const actualLines = Math.ceil(h2 / lineHeight)

                                    // 如果实际行数超过限制行数，或者高度差超过0.1行，才显示展开/收起按钮
                                    if (actualLines > lineCount || h2 > h1 + lineHeight * 0.1) {
                                        this.is_open = true
                                    } else {
                                        this.is_open = false
                                    }
                                    this.box_h = Math.ceil(h2 / lineHeight) + 1
                                    this.showall = false
                                }
                                if (res && res[2]) {
                                    let unfold_packup_width = res[2].height - 1.5 || 22
                                    this.unfold_packup_line = unfold_packup_width
                                }
                            })
                        }, 100)
                    })
                },
                deep: true,
                immediate: true,
            },
        },
    }
</script>

<!-- #endif -->

<style lang="scss">
    .zh-readMore {
        position: relative;

        .zh-readMore-wrapper {
            overflow: hidden;
            display: flex;

            .zh-text {
                position: relative;
                line-height: 1.5;
                text-align: justify;
                text-overflow: ellipsis;
                word-break: break-all;
                transition: var(--duration) max-height linear;
            }

            .zh-text::before {
                float: right;
                height: calc(100% - var(--unfold_packup_line));
                content: '';
            }

            .zh-open {
                position: relative;
                float: right;
                clear: both;
                line-height: 1.5;
                z-index: 2;

                .zh-open-text {
                    margin-left: 6rpx;
                }
            }

            .zh-fewer {
                display: inline-block;

                .zh-fewer-text {
                    margin-left: 6rpx;
                }
            }
        }
    }
    .zh-ellipsis {
        font-size: 30rpx;
        color: #434343;
    }
    .zh-overflowcont {
        position: absolute;
        top: -10000px;
        left: -10000px;
        width: 100%;
        line-height: 1.5;
        text-align: justify;
        text-overflow: ellipsis;
        word-break: break-all;

        .zh-overflowcont-text {
            display: block;
        }

        .zh-overflowcont-open {
            margin-left: 6rpx;
        }
    }
</style>
