图书馆小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
3.4 KiB

2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
  1. <template>
  2. <view class="item-container" @click="$emit('click')">
  3. <view class="item-box">
  4. <view class="item-box-left">
  5. <image
  6. class="img-item"
  7. :src="actualCover"
  8. mode="scaleToFill"
  9. @error="onImgError"
  10. ></image>
  11. </view>
  12. <view class="item-box-right">
  13. <view class="item-title line-clamp-2">{{ data.title || data.name || '暂无标题' }}</view>
  14. <text class="item-author">{{ data.author || '佚名' }}</text>
  15. <text class="item-publish">{{ data.publisher || '暂无出版社数据' }}</text>
  16. </view>
  17. </view>
  18. </view>
  19. </template>
  20. <script>
  21. export default {
  22. name: "book-list-item",
  23. props: {
  24. data: {
  25. type: Object,
  26. required: true
  27. }
  28. },
  29. computed: {
  30. actualCover() {
  31. // 优先级:base64Cover > cover > imgCover
  32. // base64Cover 是本地 base64 图片,直接使用,不需要检查
  33. if (this.data.base64Cover) {
  34. return this.data.base64Cover;
  35. }
  36. // cover 和 imgCover 需要检查有效性
  37. const cover = this.data.cover || this.data.imgCover;
  38. // 如果有封面链接,检查是否是无效域名
  39. if (cover && this.isValidCoverLink(cover)) {
  40. return cover;
  41. }
  42. // 返回默认图片
  43. return '/static/images/default-book.png';
  44. }
  45. },
  46. methods: {
  47. /**
  48. * 检查封面链接是否有效
  49. * @param {string} coverlink - 封面链接
  50. * @returns {boolean} - 是否有效
  51. */
  52. isValidCoverLink(coverlink) {
  53. if (!coverlink || typeof coverlink !== 'string') {
  54. return false;
  55. }
  56. // 检查是否包含 http
  57. if (coverlink.indexOf('http') === -1) {
  58. return false;
  59. }
  60. // 已知无法访问的域名列表
  61. const blockedDomains = [
  62. 'doubanio.com',
  63. 'douban.com'
  64. ];
  65. // 检查是否包含被阻止的域名
  66. for (const domain of blockedDomains) {
  67. if (coverlink.includes(domain)) {
  68. return false;
  69. }
  70. }
  71. return true;
  72. },
  73. /**
  74. * 图片加载失败处理
  75. */
  76. onImgError(e) {
  77. e.target.src = "/static/images/default-book.png";
  78. }
  79. }
  80. };
  81. </script>
  82. <style lang="scss" scoped>
  83. .item-container {
  84. padding-bottom: 10px;
  85. .item-box {
  86. display: flex;
  87. justify-content: flex-start;
  88. align-items: flex-start;
  89. padding: 10px;
  90. background-color: #fff;
  91. border-radius: 6px;
  92. border-bottom: 1px solid #f4f4f4;
  93. .item-box-left {
  94. margin-right: 8px;
  95. .img-item{
  96. width: 64px;
  97. height: 90px;
  98. margin: 0 12px 0 0;
  99. border-radius: 5px;
  100. }
  101. }
  102. .item-box-right {
  103. display: flex;
  104. flex-direction: column;
  105. justify-content: flex-start;
  106. flex: 1;
  107. .item-title {
  108. font-size: 15px;
  109. font-weight: bold;
  110. color: #000;
  111. padding-bottom: 10px;
  112. }
  113. .item-author,
  114. .item-publish {
  115. font-size: 12px;
  116. color: #888;
  117. padding-bottom: 10px;
  118. }
  119. .hot-text {
  120. font-size: 12px;
  121. color: #ff4444;
  122. }
  123. .item-desc {
  124. padding-top: 5px;
  125. font-size: 13px;
  126. color: #666;
  127. line-height: 1.4;
  128. }
  129. .item-bottom-box {
  130. margin-top: 8px;
  131. display: flex;
  132. justify-content: space-between;
  133. align-items: center;
  134. }
  135. }
  136. }
  137. }
  138. </style>