u-read-more.vue 4.4 KB
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
<template>
<view class="u-read-more">
<view
class="u-read-more__content"
:style="{
height: isLongContent && status === 'close' ? $u.addUnit(showHeight) : $u.addUnit(contentHeight),
textIndent: textIndent
}"
>
<view
class="u-read-more__content__inner"
ref="u-read-more__content__inner"
:class="[elId]"
>
<slot></slot>
</view>
</view>
<view
class="u-read-more__toggle"
:style="[innerShadowStyle]"
v-if="isLongContent"
>
<slot name="toggle">
<view
class="u-read-more__toggle__text"
@tap="toggleReadMore"
>
<u--text
:text="status === 'close' ? closeText : openText"
:color="color"
:size="fontSize"
:lineHeight="fontSize"
margin="0 5px 0 0"
></u--text>
<view class="u-read-more__toggle__icon">
<u-icon
:color="color"
:size="fontSize + 2"
:name="status === 'close' ? 'arrow-down' : 'arrow-up'"
></u-icon>
</view>
</view>
</slot>
</view>
</view>
</template>

<script>
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom')
// #endif
import props from './props.js';
/**
* readMore 阅读更多
* @description 该组件一般用于内容较长,预先收起一部分,点击展开全部内容的场景。
* @tutorial https://www.uviewui.com/components/readMore.html
* @property {String | Number} showHeight 内容超出此高度才会显示展开全文按钮,单位px(默认 400 )
* @property {Boolean} toggle 展开后是否显示收起按钮(默认 false )
* @property {String} closeText 关闭时的提示文字(默认 '展开阅读全文' )
* @property {String} openText 展开时的提示文字(默认 '收起' )
* @property {String} color 提示文字的颜色(默认 '#2979ff' )
* @property {String | Number} fontSize 提示文字的大小,单位px (默认 14 )
* @property {Object} shadowStyle 显示阴影的样式
* @property {String} textIndent 段落首行缩进的字符个数 (默认 '2em' )
* @property {String | Number} name 用于在 open 和 close 事件中当作回调参数返回
* @event {Function} open 内容被展开时触发
* @event {Function} close 内容被收起时触发
* @example <u-read-more><rich-text :nodes="content"></rich-text></u-read-more>
*/
export default {
name: 'u-read-more',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
isLongContent: false, // 是否需要隐藏一部分内容
status: 'close', // 当前隐藏与显示的状态,close-收起状态,open-展开状态
elId: uni.$u.guid(), // 生成唯一class
contentHeight: 100, // 内容高度
}
},
computed: {
// 展开后无需阴影,收起时才需要阴影样式
innerShadowStyle() {
if (this.status === 'open') return {}
else return this.shadowStyle
}
},
mounted() {
this.init()
},
methods: {
async init() {
this.getContentHeight().then(height => {
this.contentHeight = height
// 判断高度,如果真实内容高度大于占位高度,则显示收起与展开的控制按钮
if (height > uni.$u.getPx(this.showHeight)) {
this.isLongContent = true
this.status = 'close'
}
})
},
// 获取内容的高度
async getContentHeight() {
// 延时一定时间再获取节点
await uni.$u.sleep(30)
return new Promise(resolve => {
// #ifndef APP-NVUE
this.$uGetRect('.' + this.elId).then(res => {
resolve(res.height)
})
// #endif

// #ifdef APP-NVUE
const ref = this.$refs['u-read-more__content__inner']
dom.getComponentRect(ref, (res) => {
resolve(res.size.height)
})
// #endif
})
},
// 展开或者收起
toggleReadMore() {
this.status = this.status === 'close' ? 'open' : 'close'
// 如果toggle为false,隐藏"收起"部分的内容
if (this.toggle == false) this.isLongContent = false
// 发出打开或者收齐的事件
this.$emit(this.status, this.name)
}
}
}
</script>

<style lang="scss" scoped>
@import "../../libs/css/components.scss";

.u-read-more {

&__content {
overflow: hidden;
color: $u-content-color;
font-size: 15px;
text-align: left;
}

&__toggle {
@include flex;
justify-content: center;

&__text {
@include flex;
align-items: center;
justify-content: center;
margin-top: 5px;
}
}
}
</style>