u-read-more.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <template>
  2. <view class="">
  3. <view class="u-content" :class="[elId]" :style="{
  4. height: isLongContent && !showMore ? showHeight + 'rpx' : 'auto',
  5. textIndent: textIndent
  6. }">
  7. <slot></slot>
  8. </view>
  9. <view @tap="toggleReadMore" v-if="isLongContent" class="u-content__showmore-wrap"
  10. :class="{ 'u-content__show-more': showMore }"
  11. :style="[innerShadowStyle]">
  12. <text class="u-content__showmore-wrap__readmore-btn" :style="{
  13. fontSize: fontSize + 'rpx',
  14. color: color
  15. }">
  16. {{ showMore ? openText : closeText }}
  17. </text>
  18. <view class="u-content__showmore-wrap__readmore-btn__icon u-flex">
  19. <u-icon :color="color" :size="fontSize" :name="showMore ? 'arrow-up' : 'arrow-down'"></u-icon>
  20. </view>
  21. </view>
  22. </view>
  23. </template>
  24. <script>
  25. /**
  26. * readMore 阅读更多
  27. * @description 该组件一般用于内容较长,预先收起一部分,点击展开全部内容的场景。
  28. * @tutorial https://www.uviewui.com/components/readMore.html
  29. * @property {String Number} show-height 内容超出此高度才会显示展开全文按钮,单位rpx(默认400)
  30. * @property {Boolean} toggle 展开后是否显示收起按钮(默认false)
  31. * @property {String} close-text 关闭时的提示文字(默认“展开阅读全文”)
  32. * @property {String Number} font-size 提示文字的大小,单位rpx(默认28)
  33. * @property {String} text-indent 段落首行缩进的字符个数(默认2em)
  34. * @property {String} open-text 展开时的提示文字(默认“收起”)
  35. * @property {String} color 提示文字的颜色(默认#2979ff)
  36. * @example <u-read-more><rich-text :nodes="content"></rich-text></u-read-more>
  37. */
  38. export default {
  39. name: "u-read-more",
  40. emits: ["open", "close"],
  41. props: {
  42. // 默认的显示占位高度,单位为rpx
  43. showHeight: {
  44. type: [Number, String],
  45. default: 400
  46. },
  47. // 展开后是否显示"收起"按钮
  48. toggle: {
  49. type: Boolean,
  50. default: false
  51. },
  52. // 关闭时的提示文字
  53. closeText: {
  54. type: String,
  55. default: '展开阅读全文'
  56. },
  57. // 展开时的提示文字
  58. openText: {
  59. type: String,
  60. default: '收起'
  61. },
  62. // 提示的文字颜色
  63. color: {
  64. type: String,
  65. default: '#2979ff'
  66. },
  67. // 提示文字的大小
  68. fontSize: {
  69. type: [String, Number],
  70. default: 28
  71. },
  72. // 是否显示阴影
  73. shadowStyle: {
  74. type: Object,
  75. default () {
  76. return {
  77. backgroundImage: "linear-gradient(-180deg, rgba(255, 255, 255, 0) 0%, #fff 80%)",
  78. paddingTop: "300rpx",
  79. marginTop: "-300rpx"
  80. }
  81. }
  82. },
  83. // 段落首行缩进的字符个数
  84. textIndent: {
  85. type: String,
  86. default: '2em'
  87. },
  88. // open和close事件时,将此参数返回在回调参数中
  89. index: {
  90. type: [Number, String],
  91. default: ''
  92. }
  93. },
  94. watch: {
  95. paramsChange(val) {
  96. this.init();
  97. }
  98. },
  99. computed: {
  100. paramsChange() {
  101. return `${this.toggle}-${this.showHeight}`;
  102. },
  103. // 展开后无需阴影,收起时才需要阴影样式
  104. innerShadowStyle() {
  105. if (this.showMore) return {};
  106. else return this.shadowStyle
  107. }
  108. },
  109. data() {
  110. return {
  111. isLongContent: false, // 是否需要隐藏一部分内容
  112. showMore: false, // 当前隐藏与显示的状态,true-显示,false-收起
  113. elId: this.$u ? this.$u.guid() : uni.$u.guid(), // 生成唯一class
  114. };
  115. },
  116. mounted() {
  117. this.$nextTick(() => {
  118. this.init();
  119. this.createIntersectionObserver();
  120. })
  121. },
  122. methods: {
  123. createIntersectionObserver() {
  124. try {
  125. const observer = uni.createIntersectionObserver(this);
  126. observer.relativeToViewport().observe('.u-content', (res) => {
  127. const { height } = res.intersectionRect;
  128. //console.log('元素的高度:', height);
  129. this.init();
  130. });
  131. } catch(err){}
  132. },
  133. init() {
  134. this.$uGetRect('.' + this.elId).then(res => {
  135. // 判断高度,如果真实内容高度大于占位高度,则显示收起与展开的控制按钮
  136. if (res.height > uni.upx2px(this.showHeight)) {
  137. this.isLongContent = true;
  138. this.showMore = false;
  139. }
  140. })
  141. },
  142. // 展开或者收起
  143. toggleReadMore() {
  144. this.showMore = !this.showMore;
  145. // 如果toggle为false,隐藏"收起"部分的内容
  146. if (this.toggle == false) this.isLongContent = false;
  147. // 发出打开或者收齐的事件
  148. this.$emit(this.showMore ? 'open' : 'close', this.index);
  149. }
  150. }
  151. };
  152. </script>
  153. <style lang="scss" scoped>
  154. @import "../../libs/css/style.components.scss";
  155. .u-content {
  156. font-size: 30rpx;
  157. color: $u-content-color;
  158. line-height: 1.8;
  159. text-align: left;
  160. overflow: hidden;
  161. &__show-more {
  162. padding-top: 0;
  163. background: none;
  164. margin-top: 20rpx;
  165. }
  166. &__showmore-wrap {
  167. position: relative;
  168. width: 100%;
  169. padding-bottom: 26rpx;
  170. @include vue-flex;
  171. align-items: center;
  172. justify-content: center;
  173. &__readmore-btn {
  174. @include vue-flex;
  175. align-items: center;
  176. justify-content: center;
  177. line-height: 1;
  178. &__icon {
  179. margin-left: 14rpx;
  180. }
  181. }
  182. }
  183. }
  184. </style>