detail.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <template>
  2. <unicloud-db v-slot:default="{data, loading, error, options}" :collection="collection" :options="formData"
  3. :getone="true" :where="where" :manual="true" ref="detail" foreignKey="uni-cms-articles.user_id"
  4. @load="loadData"
  5. class="article">
  6. <template v-if="!loading && data">
  7. <view class="meta">
  8. <view class="title">
  9. <text class="text">{{ data.title }}</text>
  10. </view>
  11. <view class="excerpt">
  12. <text class="text">{{ data.excerpt }}</text>
  13. </view>
  14. <view class="author">
  15. <template v-if="data.user_id[0]">
  16. <text class="at">{{ data.user_id[0].nickname || '' }}</text>
  17. <text class="split">·</text>
  18. </template>
  19. <text class="date">{{ publishTime(data.publish_date) }}</text>
  20. </view>
  21. </view>
  22. <render-article-detail
  23. :content="data.content"
  24. :content-images="data.content_images"
  25. :ad-config="{ adpId, watchAdUniqueType }"
  26. ></render-article-detail>
  27. </template>
  28. <view class="detail-loading" v-else>
  29. <uni-icons type="spinner-cycle" size="35px"/>
  30. </view>
  31. </unicloud-db>
  32. </template>
  33. <script>
  34. import uniNavBar from '@/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue';
  35. import renderArticleDetail from "@/uni_modules/uni-cms-article/components/render-article-detail/index.vue";
  36. import translatePublishTime from "@/uni_modules/uni-cms-article/common/publish-time";
  37. const db = uniCloud.database()
  38. const articleDBName = 'uni-cms-articles'
  39. const userDBName = 'uni-id-users'
  40. export default {
  41. components: {
  42. uniNavBar,
  43. renderArticleDetail
  44. },
  45. data() {
  46. return {
  47. id: "", // 文章ID
  48. title: "", // 文章标题
  49. formData: {}, // 表单数据
  50. // 广告相关配置
  51. adpId: "", // TODO: 请填写广告位ID
  52. watchAdUniqueType: "device" // TODO: 观看广告的唯一标识类型,可选值为 user 或者 device,user 表示用户唯一,device 表示设备唯一
  53. }
  54. },
  55. computed: {
  56. where() {
  57. //拼接where条件 查询条件 ,更多详见 :https://uniapp.dcloud.net.cn/uniCloud/unicloud-db?id=jsquery
  58. return `_id =="${this.id}"`
  59. },
  60. collection() {
  61. return [
  62. db.collection(articleDBName).where(this.where).field('user_id,thumbnail,excerpt,publish_date,title,content').getTemp(),
  63. db.collection(userDBName).field('_id, nickname').getTemp()
  64. ]
  65. }
  66. },
  67. onReady() {
  68. // 开始加载数据,修改 where 条件后才开始去加载 clinetDB 的数据 ,需要等组件渲染完毕后才开始执行 loadData,所以不能再 onLoad 中执行
  69. if (this.id) { // ID 不为空,则发起查询
  70. this.$refs.detail.loadData()
  71. } else {
  72. uni.showToast({
  73. icon: 'none',
  74. title: 'id 不能为空'
  75. })
  76. }
  77. },
  78. onLoad(event) {
  79. //获取文章id,通常 id 来自上一个页面
  80. if (event.id) {
  81. this.id = event.id
  82. }
  83. // 监听解锁内容事件
  84. uni.$on('onUnlockContent', this.onUnlockContent)
  85. },
  86. onUnload() {
  87. // 页面卸载时,移除监听事件
  88. uni.$off('onUnlockContent', this.onUnlockContent)
  89. },
  90. onPageScroll(e) {
  91. // 根据滚动位置判断是否显示导航栏
  92. if (e.scrollTop > 100) {
  93. uni.setNavigationBarTitle({
  94. title: this.title
  95. })
  96. } else {
  97. uni.setNavigationBarTitle({
  98. title: ''
  99. })
  100. }
  101. },
  102. methods: {
  103. // 将时间戳转换为可读的时间格式
  104. publishTime(timestamp) {
  105. return translatePublishTime(timestamp)
  106. },
  107. // 将文章加入阅读历史
  108. setReadHistory() {
  109. // 获取阅读历史缓存,如果不存在则为空数组
  110. const historyCache = uni.getStorageSync('readHistory') || []
  111. // 过滤掉当前文章的阅读历史
  112. const readHistory = historyCache.filter(item => item.article_id !== this.id)
  113. // 将当前文章的阅读历史添加到数组最前面
  114. readHistory.unshift({
  115. article_id: this.id,
  116. last_time: Date.now()
  117. })
  118. // 将更新后的阅读历史缓存到本地
  119. uni.setStorageSync('readHistory', readHistory)
  120. },
  121. // 加载数据
  122. loadData(data) {
  123. // 设置文章标题
  124. this.title = data.title
  125. // 将文章添加进阅读历史
  126. this.setReadHistory()
  127. },
  128. // 监听解锁内容事件,解锁内容后重新加载数据
  129. async onUnlockContent() {
  130. this.$refs.detail.loadData()
  131. }
  132. }
  133. }
  134. </script>
  135. <style scoped lang="scss">
  136. /* #ifdef APP-NVUE */
  137. .article {
  138. background-color: #fff;
  139. }
  140. /* #endif */
  141. @mixin cp {
  142. padding: 0 30rpx;
  143. }
  144. .detail-loading {
  145. margin: 100rpx auto 0;
  146. width: 35px;
  147. height: 35px;
  148. animation: rotate360 2s linear infinite;
  149. }
  150. @keyframes rotate360 {
  151. 0% {
  152. transform: rotate(0deg);
  153. transform-origin: center center;
  154. }
  155. 100% {
  156. transform: rotate(360deg);
  157. transform-origin: center center;
  158. }
  159. }
  160. .meta {
  161. @include cp;
  162. position: relative;
  163. z-index: 1;
  164. padding-top: 20rpx;
  165. .title {
  166. .text {
  167. font-size: 40rpx;
  168. line-height: 66rpx;
  169. font-weight: bold;
  170. color: #333;
  171. }
  172. }
  173. .excerpt {
  174. margin-top: 10rpx;
  175. .text {
  176. font-size: 26rpx;
  177. line-height: 40rpx;
  178. color: #999;
  179. }
  180. }
  181. .author {
  182. display: flex;
  183. align-items: center;
  184. justify-content: flex-start;
  185. flex-direction: row;
  186. margin-top: 20rpx;
  187. .at,
  188. .split,
  189. .date {
  190. font-size: 26rpx;
  191. color: #ccc;
  192. }
  193. .split {
  194. margin: 0 10rpx;
  195. }
  196. }
  197. }
  198. </style>