[关闭]
@Wangww0925 2019-08-07T05:47:05.000000Z 字数 4936 阅读 189

vue-cli 瀑布流

vue-cli


注意事项

瀑布流结合了 onresize事件、onscroll事件。onresize事件主要是为了监听窗口尺寸变化;onscroll事件主要是为了滚动到底部加载更多数据

变量、函数说明:

瀑布流的实现逻辑(具体参照例子)

例子:

vue文件

  1. <template>
  2. <div>
  3. <ul class="article_list w" ref="article_list">
  4. <li class="item" v-for="(item,i) in imgsArr">
  5. <router-link :to="{path:'Detail', query: {id: item.id} }">
  6. <img class="w" :src="item.path" alt="">
  7. <p class="ti24" v-text="item.summary"></p>
  8. </router-link>
  9. </li>
  10. </ul>
  11. <div v-if="!isMore">
  12. <p class="tc" v-text="isMoreText"></p>
  13. </div>
  14. <div class="loading tc" v-if="isFirstLoad" style="font-size: 30px;">正在加载中...</div>
  15. </div>
  16. </template>
  17. <script>
  18. import store from '@/store/store';
  19. export default {
  20. store,
  21. data () {
  22. return {
  23. ajaxData:{ // 列表请求数据
  24. page: 0, // 当前加载的加载图片的次数
  25. },
  26. imgsArr: [], // 列表数据
  27. isFirstLoad:true, // loading
  28. isMore:true, // true-还有更多
  29. isMoreText:'没有更多的内容了',
  30. isPreloading:true, // 滚动到底部,并且能获取数据
  31. }
  32. },
  33. methods: {
  34. DateRenew(){ // 列表初始化
  35. this.imgsArr = []; // 列表数据
  36. this.ajaxData.page = 0; // 页码
  37. this.removeScroll();
  38. this.scroll();
  39. this.getData();
  40. },
  41. getData() { // 请求列表
  42. console.log(this.ajaxData)
  43. this.isFirstLoad = true; // loading显示
  44. this.$http.get("http://118.24.194.224:20001/api/blog/article-list")
  45. .then((res)=>{
  46. this.ajaxData.page++
  47. let result = res.data.body.data
  48. console.log(res)
  49. this.ajaxData.page == 0 ? this.imgsArr = [] : ""; // 避免多次请求出现数据重复
  50. this.imgsArr = this.imgsArr.concat(result)
  51. this.getPosition()
  52. this.isFirstLoad = false; // loading隐藏
  53. },(res)=>{
  54. console.log(res)
  55. })
  56. },
  57. getPosition() { // 不固定列宽的瀑布流
  58. let that = this;
  59. let $ul = that.$refs.article_list;
  60. let spacingW = 15; // 间距
  61. var columnNum = 2; // 一列个数
  62. // 延迟是为了解决ul下的li获取不到问题
  63. setTimeout(function (){
  64. let ulW = $ul.offsetWidth;
  65. let listArr = []; // 存放每个li的top + height值
  66. let $list = $ul.children;
  67. ulW > 900 ? columnNum = 3 : ""; // 大于宽度900的列数为 3
  68. // 如果宽度相等,不执行定位
  69. if(ulW < 700){
  70. $ul.style.height = "auto"
  71. for(var j = 0; j < $list.length; j++){
  72. $list[j].style.position = "";
  73. $list[j].style.width = "100%";
  74. $list[j].style.marginBottom = "15px";
  75. $list[j].setAttribute("class","item fadeOut");
  76. }
  77. }
  78. // 瀑布流布局逻辑
  79. if(ulW >= 700){
  80. for(var i = 0; i < $list.length; i++){
  81. $list[i].style.position = "absolute";
  82. $list[i].style.marginBottom = "0px";
  83. // 设置列宽
  84. let liW = (ulW - spacingW * (columnNum - 1)) / columnNum; // 每个宽度 = (总宽 - 间距)/ 一列个数
  85. $list[i].style.width = `${ liW }px`;
  86. // 当前列高
  87. let liH = $list[i].offsetHeight;
  88. // 设置 top 值;小于一行的个数top都为0
  89. if(i < columnNum){
  90. $list[i].style.top = 0;
  91. $list[i].style.left = `${ (liW + spacingW) * i }px`;
  92. listArr[i] = liH;
  93. }else{
  94. let minTopHeight = Math.min.apply(null, listArr); // 获取数组中的最小值
  95. let minIndex = listArr.indexOf(minTopHeight); // 获取数组中最小值的索引
  96. let liTopHeight = minTopHeight + spacingW; // 当前 top = 上一行对应列的top + 上一行对应列的height + 间距
  97. $list[i].style.top = `${ liTopHeight }px`;
  98. $list[i].style.left = `${ $list[minIndex].offsetLeft }px`; // left = 最低高的left
  99. listArr[minIndex] = $list.length * 500; // 确保下一次获取最小值时不会再次获取到;$list.length * 500 让其一定比数组中所有的值大
  100. listArr[i] = liTopHeight + liH; // 将当前top + 当前height 放到数组中
  101. }
  102. $list[i].setAttribute("class","item fadeOut");
  103. }
  104. let lastEle = $list[$list.length - 1]; // 获取最后一个li
  105. $ul.style.height = `${lastEle.offsetTop + lastEle.offsetHeight + 50 }px`; // 设置ul高度 = 最后一个li的top + 最后一个li的height + 50
  106. }
  107. // 判断无更多数据
  108. // 由于setTimeout是异步,所以isMore不能在返回数据时就判断,会照成没有更多内容提早显示,给用户造成体验不好的感觉
  109. if (that.ajaxData.page === 3) { // 模拟已经无新数据
  110. that.removeScroll()
  111. that.isMore = false;
  112. that.isPreloading = false;
  113. }else{
  114. that.isMore = true;
  115. that.isPreloading = true; // 滚动到底部还原,让其可以继续加载数据
  116. }
  117. },500)
  118. },
  119. scroll(){ // 绑定滚动事件
  120. window.addEventListener('scroll', this.scrollFun,true)
  121. },
  122. scrollFun(){ // 处理滚动事件
  123. let $ul = this.$refs.article_list;
  124. let innerHeight = $ul.clientHeight; // 可滚动容器的高度
  125. let outerHeight = document.documentElement.clientHeight; // 屏幕尺寸高度let
  126. let scrollTop = document.documentElement.scrollTop; // 可滚动容器超出当前窗口显示范围的高度
  127. // 判断滚动到底部
  128. if (innerHeight < (outerHeight + scrollTop)) {
  129. if (this.isPreloading && !this.isMore){ // 可以加载数据,并且数据没有全部加载完毕
  130. this.isPreloading = false // 滚动到底部不能加载数据,等待数据处理完毕时才可以加载数据
  131. this.getData() // 加载数据
  132. }
  133. }
  134. },
  135. removeScroll(){ // 解除滚动事件
  136. window.removeEventListener('scroll', this.scrollFun)
  137. }
  138. },
  139. created : function (){
  140. // console.log("2 - created 实例对象创建完成")
  141. this.DateRenew()
  142. },
  143. watch:{ // 监听
  144. '$store.state.windowResizeW':function(){ // 监听屏幕宽度变化
  145. this.getPosition()
  146. },
  147. '$store.state.windowResizeH':function(){ // 监听屏幕高度变化
  148. this.getPosition()
  149. }
  150. }
  151. }
  152. </script>
  153. <style scoped lang="stylus">
  154. .w
  155. width:100%;
  156. .ti34
  157. text-indent:24px;
  158. .tc
  159. text-align: center;
  160. .boxShadow
  161. box-shadow:0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12), 0 -1px 0.5px 0 rgba(0,0,0,0.09);
  162. vendor(prop, n)
  163. -webkit-{prop}:n;
  164. -moz-{prop}:n;
  165. -ms-{prop}:n;
  166. -o-{prop}:n;
  167. {prop}:n;
  168. .item
  169. width:100%;
  170. background-color:#fff;
  171. padding:10px;
  172. opacity:0;
  173. vendor('transition',opacity 2s)
  174. &:hover
  175. vendor('transform', translateY(-1px));
  176. box-shadow: 0 1px 3px rgba(0,0,0,.02), 0 9px 15px -4px rgba(0,0,0,.17);
  177. .fadeOut
  178. opacity:1;
  179. .loading
  180. height:50px;
  181. line-height:50px;
  182. text-align:center;
  183. @media screen and (min-width: 992px)
  184. .article_list
  185. position:relative;
  186. .item
  187. @extend .boxShadow;
  188. </style>

作者 wendy
2019 年 1月 4日


参考文献

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注