long-list-page.uvue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <template>
  2. <list-view :id="id" class="list" :bounces="false" :scroll-y="true" :custom-nested-scroll="true"
  3. @scrolltolower="loadData(null)" associative-container="nested-scroll-view">
  4. <list-item class="list-item" v-for="(item, _) in dataList" :key="item.plugin_id" type="10">
  5. <view class="list-item-icon">
  6. <image class="list-item-icon-image" :src="item.plugin_img_link"></image>
  7. </view>
  8. <view class="list-item-fill">
  9. <view class="flex-row">
  10. <text class="title">{{item.plugin_name}}</text>
  11. </view>
  12. <view>
  13. <text class="description-text">{{item.plugin_intro}}</text>
  14. </view>
  15. <text class="icon-star">{{convertToStarUnicode(item.score)}}</text>
  16. <view class="tag-list">
  17. <text class="tag-item" v-for="(item2, index2) in item.tags" :key="index2">{{item2}}</text>
  18. </view>
  19. <view class="flex-row update-date">
  20. <text class="update-date-text">更新日期</text>
  21. <text class="update-date-value">{{item.update_date}}</text>
  22. <text class="author">{{item.author_name}}</text>
  23. </view>
  24. </view>
  25. </list-item type="20">
  26. <list-item class="loading">
  27. <uni-loading :loading="loading" color="#999" :text="loadingText"></uni-loading>
  28. </list-item>
  29. </list-view>
  30. </template>
  31. <script>
  32. const SERVER_URL = "https://unidemo.dcloud.net.cn/plugin/uniappx-plugin-list"
  33. const PAGE_SIZE = 10; // 最大值 10
  34. type ListItem = {
  35. plugin_id : number,
  36. plugin_img_link : string,
  37. plugin_name : string,
  38. plugin_intro : string,
  39. score : number,
  40. tags : Array<string>,
  41. update_date : string,
  42. author_name : string,
  43. }
  44. type ResponseDataType = {
  45. code : number,
  46. data : ListItem[]
  47. }
  48. export default {
  49. props: {
  50. type: {
  51. type: String,
  52. default: ''
  53. },
  54. preload: {
  55. type: Boolean,
  56. default: false
  57. },
  58. id: {
  59. type: String,
  60. default: ''
  61. }
  62. },
  63. data() {
  64. return {
  65. loading: false,
  66. dataList: [] as ListItem[],
  67. isEnded: false,
  68. loadingError: '',
  69. currentPage: 1
  70. }
  71. },
  72. computed: {
  73. loadingText() : string {
  74. if (this.loading) {
  75. return "加载中..."
  76. } else if (this.isEnded) {
  77. return "没有更多了"
  78. } else if (this.loadingError.length > 0) {
  79. return this.loadingError
  80. } else {
  81. return ""
  82. }
  83. }
  84. },
  85. created() {
  86. if (this.preload) {
  87. this.loadData(null)
  88. }
  89. },
  90. methods: {
  91. refreshData(loadComplete : (() => void) | null) {
  92. this.dataList.length = 0
  93. this.currentPage = 1
  94. this.loadData(loadComplete)
  95. },
  96. loadData(loadComplete : (() => void) | null) {
  97. if (this.loading || this.isEnded) {
  98. return
  99. }
  100. this.loading = true
  101. uni.request<ResponseDataType>({
  102. url: SERVER_URL,
  103. data: {
  104. type: this.type,
  105. page: this.currentPage,
  106. page_size: PAGE_SIZE
  107. },
  108. success: (res) => {
  109. const responseData = res.data
  110. if (responseData == null) {
  111. return
  112. }
  113. this.dataList.push(...responseData.data)
  114. if (responseData.data.length == 0) {
  115. this.isEnded = true
  116. } else {
  117. this.currentPage++
  118. }
  119. },
  120. fail: (err) => {
  121. this.loadingError = err.errMsg
  122. },
  123. complete: () => {
  124. this.loading = false
  125. if (loadComplete != null) {
  126. loadComplete()
  127. }
  128. }
  129. })
  130. },
  131. // score 0 ~ 50
  132. convertToStarUnicode(score : number) : string {
  133. const fill_code = '\ue879'
  134. const half_code = '\ue87a'
  135. const null_code = '\ue87b'
  136. const fillStarCount = parseInt(score / 10 % 10 + '')
  137. const halfStarCount = score % 10 >= 5 ? 1 : 0
  138. const nullStarCount = 5 - fillStarCount - halfStarCount
  139. let result = ''
  140. if (fillStarCount > 0) { result += fill_code.repeat(fillStarCount) }
  141. if (halfStarCount > 0) { result += half_code.repeat(halfStarCount) }
  142. if (nullStarCount > 0) { result += null_code.repeat(nullStarCount) }
  143. return result
  144. }
  145. }
  146. }
  147. </script>
  148. <style>
  149. @font-face {
  150. font-family: "UtsStarIcons";
  151. src: url('@/static/fonts/icon-star.ttf');
  152. }
  153. .list {
  154. flex: 1;
  155. background-color: #ffffff;
  156. }
  157. .list-item {
  158. flex-direction: row;
  159. margin-top: 10px;
  160. padding: 10px;
  161. }
  162. .list-item-icon {
  163. position: relative;
  164. }
  165. .list-item-icon-image {
  166. width: 80px;
  167. height: 80px;
  168. }
  169. .list-item-fill {
  170. flex: 1;
  171. margin-left: 15px;
  172. }
  173. .description-text {
  174. font-size: 13px;
  175. color: #666;
  176. line-height: 19px;
  177. }
  178. .icon-star {
  179. font-family: "UtsStarIcons";
  180. font-size: 16px;
  181. font-style: normal;
  182. color: #ffca3e;
  183. letter-spacing: 3px;
  184. }
  185. .tag-list {
  186. flex-direction: row;
  187. margin-top: 5px;
  188. }
  189. .tag-item {
  190. font-size: 12px;
  191. background-color: #EFF9F0;
  192. color: #639069;
  193. border-radius: 20px;
  194. margin-right: 5px;
  195. padding: 2px 5px;
  196. }
  197. .update-date {
  198. margin-top: 10px;
  199. }
  200. .update-date-text {
  201. font-size: 12px;
  202. color: #888888;
  203. }
  204. .update-date-value {
  205. font-size: 12px;
  206. color: #777777;
  207. margin-left: 5px;
  208. }
  209. .author {
  210. font-size: 12px;
  211. color: #008000;
  212. margin-left: auto;
  213. }
  214. .loading {
  215. padding: 30px;
  216. align-items: center;
  217. }
  218. .flex-row {
  219. flex-direction: row;
  220. }
  221. </style>