ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 1像素线 ~~~ @mixin border-1px($color) { position: relative; &:after { display: block; position: absolute; left: 0; bottom: 0; width: 100%; border-top: 1px solid $color; content: ''; } } @media (-webkit-min-device-pixel-radio: 1.5), (min-device-pixel-radio: 1.5) { .border-1px { &::after { -webkit-transform: scaleY(.7); transform: scaleY(.7); } } } @media (-webkit-min-device-pixel-radio: 2), (min-device-pixel-radio: 2) { .border-1px { &::after { -webkit-transform: scaleY(.5); transform: scaleY(.5); } } } @mixin border-none { &:after { border: none; } } ~~~ 使用 ~~~ <li class="food-item border-1px"></li> .food-item { @include border-1px(rgba(7, 17, 27, 0.1)); } ~~~ ## 2倍图、3倍图 ~~~ @mixin bg-image($url) { background-image: url($url + '@2x.png'); @media (-webkit-min-device-pixel-ratio: 3), (-min-device-pixel-ratio: 3) { background-image: url($url + '@3x.png'); } } ~~~ ## 清除浮动 ~~~ .clearfix { display: inline-block; &:after { display: block; content: '.'; height: 0; line-height: 0; clear: both; visibility: hidden; } } ~~~ ## 模糊 ### backdrop-filter 只支持ios端;只作用于当前元素; 适用场景: ![](https://box.kancloud.cn/6bc39f382ce9882f58186c95919eea04_325x572.png) 为背景添加模糊效果;如果目标元素内包裹着其他内容 则应用filter属性; (不支持安卓,效果不明显) ### filter 兼容性比较好,不仅仅作用于当前元素,后代元素也会继承这个属性,**作用于一个空背景元素没有效果** 适用场景: ![](https://box.kancloud.cn/44aac8a52b70d31f99f527829dd3ddfd_318x137.png) (效果其实还是通过作用于具体的img元素才实现模糊效果,如果单单作用于一个空元素背景 则没有效果) ## 左栏固定,右栏自适应 ~~~ <template> <div class="goods"> <div class="menu-wrapper" ref="menuWrapper"></div> <div class="foods-wrapper" ref="foodsWrapper"></div> </template> <style lang="scss"> .goods { display: flex; .menu-wrapper { flex: 0 0 80px; width: 80px; } .foods-wrapper { flex: 1; } } </style> ~~~ ## 左右滚动联动 ~~~ <template> <div class="goods"> <div class="menu-wrapper" ref="menuWrapper"> <ul> <li v-for="(item, index) in goods" :class="{current: currentIndex === index}" @click="selectMenu(index, $event)"> </li> </ul> </div> <div class="foods-wrapper" ref="foodsWrapper"> <ul> <li v-for="item in goods" :key="item.id" class="food-list" ref="foodList"> <ul> <li v-for="food in item.foods" :key="food.id" class="food-item border-1px"></li> </ul> </li> </ul> </div> </div> </template> <script> data () { return { goods: [], listHeight: [], scrollY: 0 } }, computed: { // 获取当前左栏tab index currentIndex () { for (let i = 0; i < this.listHeight.length; i++) { let height1 = this.listHeight[i] let height2 = this.listHeight[i + 1] if (!height2 || (this.scrollY >= height1 && this.scrollY < height2)) { return i } } return 0 } }, created () { // 获取数据后初始化滚动插件、计算高度 this.$http.get('/api/goods').then((res) => { res = res.data if (res.errno === ERR_OK) { this.goods = res.data this.$nextTick(() => { this._initScroll() this._calculateHeight() }) } }) }, methods: { // 点击左栏tab事件 selectMenu (index, event) { if (!event._constructed) { return } let foodList = this.$refs.foodList let el = foodList[index] this.foodsScroll.scrollToElement(el, 300) }, // 初始化左右BScroll,添加右栏滚动事件 _initScroll () { this.menuScroll = new BScroll(this.$refs.menuWrapper, { click: true }) this.foodsScroll = new BScroll(this.$refs.foodsWrapper, { click: true, probeType: 3 // 在滑动、momentum 滚动动画运行过程派发 scroll 事件 }) this.foodsScroll.on('scroll', (pos) => { // 判断滑动方向,避免下拉时分类高亮错误(如第一分类商品数量为1时,下拉使得第二分类高亮) if (pos.y <= 0) { this.scrollY = Math.abs(Math.round(pos.y)) } }) }, // 计算、存储各个分类的scrollTop值到listHeight _calculateHeight () { let foodList = this.$refs.foodList let height = 0 this.listHeight.push(height) for (let i = 0; i < foodList.length; i++) { let item = foodList[i] height += item.clientHeight this.listHeight.push(height) } } } </script> ~~~ ## 从右到左飞入动画 ~~~ <template> <transition name="move"> <div v-show="showFlag" class="food"></div> </transition> </template> <style lang="scss"> .food { transform: translate3d(0, 0, 0); &.move-enter-active, &.move-leave-active { transition: all 0.2 s linear; } &.move-enter, &.move-leave-active { transform: translate3d(100%, 0, 0) } } </style> ~~~ ## 设置容器宽高相等 当padding使用百分百单位时,其计算是相对于宽度 ~~~ <template> <div class="image-header"> <img :src="food.image"> </div> </template> <style lang="scss"> .image-header { position: relative; width: 100%; height: 0; padding-top: 100%; img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } </style> ~~~ ## 子组件不能修改props属性 Vue 2中子组件不能修改props属性,需要通过$emit触发父组件的方法来修改 ~~~ // 父组件 <ratingSelect @select="selectRating" @toggle="toggleContent" :selectType="selectType" :onlyContent="onlyContent" :desc="desc" :ratings="food.ratings"></ratingSelect> <script> const ALL = 2 export default { props: { food: { type: Object } }, data () { return { selectType: ALL, onlyContent: true, desc: { all: '全部', positive: '推荐', negative: '吐槽' } } }, methods: { selectRating (type) { this.selectType = type this.$nextTick(() => { this.scroll.refresh() }) }, toggleContent () { this.onlyContent = !this.onlyContent this.$nextTick(() => { this.scroll.refresh() }) } }, components: { cartcontrol, split, ratingSelect } } </script> // 子组件 <template> <div class="ratingselect"> <div class="rating-type border-1px"> <span @click="select(2,$event)" class="block positive" :class="{'active':selectType===2}"> {{desc.all}}<span class="count">{{ratings.length}}</span> </span> </div> <div @click="toggleContent" class="switch" :class="{'on':onlyContent}"> <span class="icon-check_circle"></span> <span class="text">只看有内容的评价</span> </div> </div> </template> <script> const POSITIVE = 0 const NEGATIVE = 1 const ALL = 2 export default { props: { ratings: { type: Array, default () { return [] } }, selectType: { type: Number, default: ALL }, onlyContent: { type: Boolean, default: false }, desc: { type: Object, default () { return { all: '全部', positive: '满意', negative: '不满意' } } } }, methods: { select (type, event) { this.$emit('select', type) }, toggleContent (event) { this.$emit('toggle') } } } </script> ~~~ ## 修改格式化时间戳 ~~~ export function formatDate (date, fmt) { if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)) } let o = { 'M+': date.getMonth() + 1, 'd+': date.getDate(), 'h+': date.getHours(), 'm+': date.getMinutes(), 's+': date.getSeconds() } for (let k in o) { if (new RegExp(`(${k})`).test(fmt)) { let str = o[k] + '' fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str)) } } return fmt } function padLeftZero (str) { return ('00' + str).substr(str.length) } ~~~