u-read-more.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <template>
  2. <view class="u-read-more">
  3. <view
  4. class="u-read-more__content"
  5. :style="{
  6. height: isLongContent && status === 'close' ? addUnit(showHeight) : addUnit(contentHeight),
  7. textIndent: textIndent
  8. }"
  9. >
  10. <view
  11. class="u-read-more__content__inner"
  12. ref="u-read-more__content__inner"
  13. :class="[elId]"
  14. >
  15. <slot></slot>
  16. </view>
  17. </view>
  18. <view
  19. class="u-read-more__toggle"
  20. :style="[innerShadowStyle]"
  21. v-if="isLongContent"
  22. >
  23. <slot name="toggle">
  24. <view
  25. class="u-read-more__toggle__text"
  26. @tap="toggleReadMore"
  27. >
  28. <up-text
  29. :text="status === 'close' ? closeText : openText"
  30. :color="color"
  31. :size="fontSize"
  32. :lineHeight="fontSize"
  33. margin="0 5px 0 0"
  34. ></up-text>
  35. <view class="u-read-more__toggle__icon">
  36. <u-icon
  37. :color="color"
  38. :size="fontSize + 2"
  39. :name="status === 'close' ? 'arrow-down' : 'arrow-up'"
  40. ></u-icon>
  41. </view>
  42. </view>
  43. </slot>
  44. </view>
  45. </view>
  46. </template>
  47. <script>
  48. // #ifdef APP-NVUE
  49. const dom = uni.requireNativePlugin('dom')
  50. // #endif
  51. import { props } from './props';
  52. import { mpMixin } from '../../libs/mixin/mpMixin';
  53. import { mixin } from '../../libs/mixin/mixin';
  54. import { addUnit, guid, getPx, sleep } from '../../libs/function/index';
  55. /**
  56. * readMore 阅读更多
  57. * @description 该组件一般用于内容较长,预先收起一部分,点击展开全部内容的场景。
  58. * @tutorial https://ijry.github.io/uview-plus/components/readMore.html
  59. * @property {String | Number} showHeight 内容超出此高度才会显示展开全文按钮,单位px(默认 400 )
  60. * @property {Boolean} toggle 展开后是否显示收起按钮(默认 false )
  61. * @property {String} closeText 关闭时的提示文字(默认 '展开阅读全文' )
  62. * @property {String} openText 展开时的提示文字(默认 '收起' )
  63. * @property {String} color 提示文字的颜色(默认 '#2979ff' )
  64. * @property {String | Number} fontSize 提示文字的大小,单位px (默认 14 )
  65. * @property {Object} shadowStyle 显示阴影的样式
  66. * @property {String} textIndent 段落首行缩进的字符个数 (默认 '2em' )
  67. * @property {String | Number} name 用于在 open 和 close 事件中当作回调参数返回
  68. * @event {Function} open 内容被展开时触发
  69. * @event {Function} close 内容被收起时触发
  70. * @example <u-read-more><rich-text :nodes="content"></rich-text></u-read-more>
  71. */
  72. export default {
  73. name: 'u-read-more',
  74. mixins: [mpMixin, mixin, props],
  75. data() {
  76. return {
  77. isLongContent: false, // 是否需要隐藏一部分内容
  78. status: 'close', // 当前隐藏与显示的状态,close-收起状态,open-展开状态
  79. elId: guid(), // 生成唯一class
  80. contentHeight: 100, // 内容高度
  81. }
  82. },
  83. computed: {
  84. // 展开后无需阴影,收起时才需要阴影样式
  85. innerShadowStyle() {
  86. if (this.status === 'open') return {}
  87. else return this.shadowStyle
  88. }
  89. },
  90. mounted() {
  91. this.init()
  92. },
  93. emits: ["open", "close"],
  94. methods: {
  95. addUnit,
  96. async init() {
  97. this.getContentHeight().then(height => {
  98. this.contentHeight = height
  99. // 判断高度,如果真实内容高度大于占位高度,则显示收起与展开的控制按钮
  100. if (height > getPx(this.showHeight)) {
  101. this.isLongContent = true
  102. this.status = 'close'
  103. } else {
  104. // https://github.com/ijry/uview-plus/issues/270
  105. this.isLongContent = false
  106. this.status = 'close'
  107. }
  108. })
  109. },
  110. // 获取内容的高度
  111. async getContentHeight() {
  112. // 延时一定时间再获取节点
  113. await sleep(30)
  114. return new Promise(resolve => {
  115. // #ifndef APP-NVUE
  116. this.$uGetRect('.' + this.elId).then(res => {
  117. resolve(res.height)
  118. })
  119. // #endif
  120. // #ifdef APP-NVUE
  121. const ref = this.$refs['u-read-more__content__inner']
  122. dom.getComponentRect(ref, (res) => {
  123. resolve(res.size.height)
  124. })
  125. // #endif
  126. })
  127. },
  128. // 展开或者收起
  129. toggleReadMore() {
  130. this.status = this.status === 'close' ? 'open' : 'close'
  131. // 如果toggle为false,隐藏"收起"部分的内容
  132. if (this.toggle == false) this.isLongContent = false
  133. // 发出打开或者收齐的事件
  134. this.$emit(this.status, this.name)
  135. }
  136. }
  137. }
  138. </script>
  139. <style lang="scss" scoped>
  140. @import "../../libs/css/components.scss";
  141. .u-read-more {
  142. &__content {
  143. overflow: hidden;
  144. color: $u-content-color;
  145. font-size: 15px;
  146. text-align: left;
  147. }
  148. &__toggle {
  149. @include flex;
  150. justify-content: center;
  151. position: relative;
  152. &__text {
  153. @include flex;
  154. align-items: center;
  155. justify-content: center;
  156. margin-top: 5px;
  157. }
  158. }
  159. }
  160. </style>