tn-read-more.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <template>
  2. <view>
  3. <view class="tn-read-more-class tn-read-more">
  4. <!-- 内容 -->
  5. <view
  6. :id="elId"
  7. class="tn-read-more__content"
  8. :style="[contentStyle]"
  9. >
  10. <slot></slot>
  11. </view>
  12. <!-- 展开收起按钮 -->
  13. <view
  14. v-if="isLongContent"
  15. class="tn-read-more__show-more__wrap"
  16. :class="{'tn-read-more__show-more': showMore}"
  17. :style="[innerShadowStyle]"
  18. @tap="toggleReadMore">
  19. <text class="tn-read-more__show-more--text" :style="[fontStyle]">{{ showMore ? closeText : openText }}</text>
  20. <view class="tn-read-more__show-more--icon">
  21. <view :class="[tipIconClass]" :style="[fontStyle]"></view>
  22. </view>
  23. </view>
  24. </view>
  25. </view>
  26. </template>
  27. <script>
  28. import componentsColorMixin from '../../libs/mixin/components_color.js'
  29. export default {
  30. name: 'tn-read-more',
  31. mixins: [componentsColorMixin],
  32. props: {
  33. // 默认占位高度
  34. showHeight: {
  35. type: Number,
  36. default: 400
  37. },
  38. // 显示收起按钮
  39. closeBtn: {
  40. type: Boolean,
  41. default: false
  42. },
  43. // 展开提示文字
  44. openText: {
  45. type: String,
  46. default: '展开阅读全文'
  47. },
  48. // 收起提示文字
  49. closeText: {
  50. type: String,
  51. default: '收起'
  52. },
  53. // 展开提示图标
  54. openIcon: {
  55. type: String,
  56. default: 'down'
  57. },
  58. // 收起提示图标
  59. closeIcon: {
  60. type: String,
  61. default: 'up'
  62. },
  63. // 阴影样式
  64. shadowStyle: {
  65. type: Object,
  66. default () {
  67. return {
  68. backgroundImage: "linear-gradient(-180deg, rgba(255, 255, 255, 0) 0%, #fff 80%)",
  69. paddingTop: "300rpx",
  70. marginTop: "-300rpx"
  71. }
  72. }
  73. },
  74. // 组件标识
  75. index: {
  76. type: [Number, String],
  77. default: ''
  78. }
  79. },
  80. computed: {
  81. paramsChange() {
  82. return `${this.open}-${this.showHeight}`
  83. },
  84. contentStyle() {
  85. let style = {}
  86. if (this.isLongContent && !this.showMore) {
  87. style.height = `${this.showHeight}rpx`
  88. } else {
  89. if (!this.initHeight) {
  90. style.height = 'auto'
  91. } else {
  92. style.height = `${this.contentHeight}px`
  93. }
  94. }
  95. return style
  96. },
  97. innerShadowStyle() {
  98. let style = {}
  99. // 折叠时才需要阴影样式
  100. if (!this.showMore) {
  101. style = Object.assign(style, this.shadowStyle)
  102. }
  103. return style
  104. },
  105. fontStyle() {
  106. let style = {}
  107. style.color = this.fontColorStyle ? this.fontColorStyle : '#01BEFF'
  108. style.fontSize = this.fontSizeStyle ? this.fontSizeStyle : '28rpx'
  109. return style
  110. },
  111. tipIconClass() {
  112. if (this.showMore) {
  113. if (this.closeIcon) {
  114. return `tn-icon-${this.closeIcon}`
  115. }
  116. } else {
  117. if (this.openIcon) {
  118. return `tn-icon-${this.openIcon}`
  119. }
  120. }
  121. }
  122. },
  123. data() {
  124. return {
  125. elId: this.$t.uuid(),
  126. // 标记是否已经初始化高度完成
  127. initHeight: false,
  128. // 是否需要隐藏一部分内容
  129. isLongContent: false,
  130. // 当前展开的打开、关闭状态
  131. showMore: false,
  132. // 内容的高度
  133. contentHeight: 0
  134. }
  135. },
  136. watch: {
  137. paramsChange(value) {
  138. this.initHeight = false
  139. this.isLongContent = false
  140. this.showMore = true
  141. this.$nextTick(() => {
  142. this.init()
  143. })
  144. }
  145. },
  146. mounted() {
  147. this.$nextTick(() => {
  148. this.init()
  149. })
  150. },
  151. methods: {
  152. // 初始化组件
  153. init() {
  154. // 判断高度,如果真实内容的高度大于占位高度,则显示展开与收起的控制按钮
  155. this._tGetRect('#' + this.elId).then(res => {
  156. this.contentHeight = res.height
  157. this.initHeight = true
  158. if (res.height > uni.upx2px(this.showHeight)) {
  159. this.isLongContent = true
  160. this.showMore = false
  161. }
  162. })
  163. },
  164. // 展开或者收起内容
  165. toggleReadMore() {
  166. this.showMore = !this.showMore
  167. // 是否显示收起按钮
  168. if (!this.closeBtn) this.isLongContent = false
  169. this.$emit(this.showMore ? 'open' : 'closed', this.index)
  170. }
  171. }
  172. }
  173. </script>
  174. <style lang="scss" scoped>
  175. .tn-read-more {
  176. &__content {
  177. font-size: 28rpx;
  178. color: $tn-font-color;
  179. line-height: 1.8;
  180. text-align: left;
  181. overflow: hidden;
  182. transition: all 0.3s linear;
  183. }
  184. &__show-more {
  185. padding-top: 0;
  186. background: none;
  187. margin-top: 20rpx;
  188. &__wrap {
  189. position: relative;
  190. width: 100%;
  191. display: flex;
  192. flex-direction: row;
  193. align-items: center;
  194. justify-content: center;
  195. padding-bottom: 26rpx;
  196. }
  197. &--text {
  198. display: flex;
  199. flex-direction: row;
  200. align-items: center;
  201. justify-content: center;
  202. line-height: 1;
  203. }
  204. &--icon {
  205. margin-left: 14rpx;
  206. }
  207. }
  208. }
  209. </style>