应用里需要做一个瀑布流的页面，类似于小红书的首页，今天终于比较完美地把这个页面做完，记录总结一下思路，分享给大家。第一部分：CSS将页面分成左右两列，左边循环一个数组，右边循环一个数组。在data里，给左右两列的div设置一个初始高度为0。从后端获取数据的时候，对后端数组进行循环处理，根据左右两列的div高度，决定把当前对象分给左边还是右边的数组。每次分配的时候，根据元素的高低，把左/右边div的高度新增上去，以便下一个对象分配的时候使用。元素的高需要大家根据自身情况判断，比如图片高度、标题的高度等等，自己判断一下有几种情况。比如我的元素里，图片的高度是比较固定的，影响高度的主要是标题的行数，就根据标题的字数进行判断每个元素的整体高度。// 获取当前页的清单数据，pageNum默认为1，hasMore默认为true async getLists(pageNum) { if (this.hasMore) { // 如果hasMore是true,就可以继续去获取数据 const moreLists = await ListService.getLists(pageNum) this.moreLists = moreLists // 如果获取到的lists为空,说明没有更多数据了,将hasMore改成false,页面提示"没有更多数据"了 if (moreLists.length === 0) { this.hasMore = false // 如果已经没有更多数据了,就取消监听窗口变化,因为全部数据都展示出来了不需要再监听 window.removeEventListener('scroll', this.monitorScrollToEnd) return } // 将获取的数据添加到lists中 for (let list of moreLists) { this.lists.push(list) } // 将获取到的数据分列 this.spiltList() } }, // 将获取到的数据，分为左右两列 spiltList() { // 定义变量，接受list数据源 let data = {} for (let i = 0; i < this.moreLists.length; i++) { // 每次只处理新增的lists data = this.moreLists[i] if (this.heightOfLeft <= this.heightOfRight) { // 如果左边矮，就放到左边 this.listLeft.push(data) // console.log('左边有' + this.listLeft) // 根据自己的元素逻辑更新容器的高度 if (data.listTitle.length <= 10) { this.heightOfLeft = this.heightOfLeft + 249.67 } else { this.heightOfLeft = this.heightOfLeft + 271.67 } // console.log( // '左边高变成' + this.heightOfLeft + '右边高是' + this.heightOfRight // ) } else { // 如果右边矮，就放到右边 this.listRight.push(data) // console.log('右边有' + this.listRight) // 根据自己的元素逻辑更新容器的高度 if (data.listTitle.length <= 10) { this.heightOfRight = this.heightOfRight + 249.67 } else { this.heightOfRight = this.heightOfRight + 271.67 } // console.log( // '右边高变成' + this.heightOfRight + '左边高是' + this.heightOfLeft // ) } } // 数据处理完后，重新启动监听 window.addEventListener('scroll', this.monitorScrollToEnd) }, 第二部分：页面加载完后，开始监听窗口高度，如果已经滚动到最下面，就向后台请求下一页的数据。这里注意触发请求时，要暂时关闭监听，否则就会出现一连串请求的情况，一下子给请求个七八次。等到新的数据加载完后，再重新启动监听即可。做完这一部分就可以实现瀑布流无限加载到最后。mounted() { // 监听窗口变化 window.addEventListener('scroll', this.monitorScrollToEnd) }, monitorScrollToEnd() { var scrollTop = document.documentElement.scrollTop || document.body.scrollTop var windowHeight = document.documentElement.clientHeight || document.body.clientHeight var scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight // 滚动到底部触发 if (Math.round(scrollTop) + windowHeight > scrollHeight - 220) { // 暂时取消监听，等数据都拿到了再重启监听 window.removeEventListener('scroll', this.monitorScrollToEnd) // 获取下一页的数据 this.pageNum += 1 // 页数加1 // 要解决触发后连续触发的问题 this.getLists(this.pageNum) // 获取下一页数据 } }, 第三部分：由于开启了窗口高度监听，这时候如果跳到详情页，或者其它页面的时候，会发现窗口监听还会继续存活，在别的页面滚动窗口，瀑布流页面还是会不断地加载加载，这个问题就需要使用路由守卫来解决。具体就是设置当路由变化的时候，取消窗口监听事件，当然回到页面的时候，要重新启动窗口监听。这里有一个坑是beforeRouteLeave千万不要使用箭头函数，否则会获取不到this，感谢知乎大拿的解答。beforeRouteLeave: function (to, from, next) { // 获取当前高度 let scrollTop = document.documentElement.scrollTop || document.body.scrollTop // 缓存当前高度 sessionStorage.setItem('scrollTop', scrollTop) // 取消监听窗口变化，否则在别的路径页面也会继续监听 window.removeEventListener('scroll', this.monitorScrollToEnd) next() }, 第四部分：下一个问题就是，瀑布流页面加载到前几屏了，这时候访问了其它路由，又回来的时候，会发现页面会被重新加载，导致瀑布流又回到了顶部。这个问题也很麻烦。解决的办法是使用keep-alive功能，将这个页面保存在缓存中。同时在离开这个路由的时候，将当前页面的高度缓存到sessionStorage里，等回到瀑布流页面，使用scrollTo直接跳转到缓存的位置，即可无感保留瀑布流的位置。// 第一步：在route/index.js中，添加meta const routes = [ { path: '/', name: 'HomePage', component: HomePage, meta: { keepAlive: true, }, }, ] // 第二步：在App.vue中，添加keep-alive标签 <router-view v-if="$route.meta.keepAlive" /> <router-view v-if="!$route.meta.keepAlive" /> // 第三步：跳出路由时，获取并缓存当前的高度 beforeRouteLeave: function (to, from, next) { // 获取当前高度 let scrollTop = document.documentElement.scrollTop || document.body.scrollTop // 缓存当前高度 sessionStorage.setItem('scrollTop', scrollTop) // 取消监听窗口变化，否则在别的路径页面也会继续监听 window.removeEventListener('scroll', this.monitorScrollToEnd) next() }, // 第四步：页面被重新激活时，获取缓存中的高度，并scrollTo缓存位置，同时重新启动监听窗口 activated() { if (sessionStorage.getItem('scrollTop') !== 0) { window.scrollTo(0, sessionStorage.getItem('scrollTop')) } // 监听窗口变化 window.addEventListener('scroll', this.monitorScrollToEnd) }, 做完这些，基本上就是一个比较完善的瀑布流页面了，参考了很多前辈的总结。如果大家还有疑问，欢迎加我微信交流，微信号：zdplist
碰到一个奇葩的事情，使用箭头函数的时候，无法获得this，不使用才能获取，真是无语。// 这样不行 beforeRouteLeave: (to, from, next) => {} // 这样可以 beforeRouteLeave: function (to, from, next) {} 这不是搞笑么。
最基础的用法，只需要添加purge如下配置即可，会自动删除没有用到的class，这太牛逼了。// tailwind.config.js module.exports = { purge: [ './src/**/*.html', './src/**/*.vue', './src/**/*.jsx', ], theme: {}, variants: {}, plugins: [], } 全部用法
安装：npm install -D webpack-bundle-analyzer配置package.json：build里加上--report"scripts": {"serve": "vue-cli-service serve", "build": "vue-cli-service build --report"},配置vue.config.js自动打开分析报告var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;module.exports = {configureWebpack: { plugins: [ new BundleAnalyzerPlugin({ openAnalyzer: false, // 在默认浏览器中是否自动打开报告，默认 true }) ] }}
宽750状态栏高40px导航栏高88px导航栏功能图标48px*48px标签tab栏高98px全局左右padding 24px卡片距离20px 24px 30px 40px 60px宽1125状态栏高132px导航栏高132px导航栏功能图标72px*72px标签tab栏高147px全局左右padding 32px卡片距离20px 24px 30px 40px 60px常用字体大小建议：标题17pt副标题14pt-17pt正文12pt—16pt注释11pt—12pt最小可见10pt参考文章
首先，如果是引用外部字体的话，需要用 把字体引入到head里。其次，head里添加script tailwind.config = { theme: { fontFamily: { sans: ['', ''], serif: ['', ''], mono: ['', ''], } } } 就可以在class里使用font-sans这样了。