使用Vue制作切口盒子组件

发布于 大漠

今天看到@Chris Coyier刚发的一篇帖子,使用CSS怎么写一个切口盒子(Notched Boxes)?其实这个效果早在@Lea Verou的CSS Secrets一书中有一个专门的小节介绍CSS怎么实现这个斜切口的效果。所以说这不是什么新东西。不过接下来的内容和前面还是略有不同。

使用到的技术

@Lea Verou曾经介绍了几种实现盒子斜切口的效果,比如说使用CSS的linear-gradientclip-path等。那么接下来的的内容其实除了运用到了clip-path之外,还使用了CSS的自定义属性以及CSS的calc()函数。从单个技术点上而言,或许大家都清楚他们的特性,或者很多同学都能灵活的使用这些CSS特性。那么今天重新花一篇篇幅来介绍,主要是因为:

clip-pathcalc()和CSS自定义变量结合一起来使用,制作切口盒子会变得很容易,也很灵活。

实现过程

还是看看为什么结合他们,会让我们事情变得更轻松。

首先来看clip-path。对于了解过clip-path的同学来说,这个不是很难的事情,在clip-path中提供了一个polygon()函数,在这个函数中我们可以传很多个点的坐标(通过每个点的xy来确定点在Web坐标系统中的位置),这样一来,我们就可以借助polygon()绘制出任意你想要的多边形。比如下面的代码,绘制了一个三角形:

.module {
    clip-path: 
        polygon(
            50% 0,
            100% 100%,
            0 100%
        );
}

效果如下:

随着点的位置增加,你就可以得到一个带斜切角的盒子:

.module {
    clip-path: 
        polygon(
            0% 5%,     /* 左上1 */
            5% 0%,     /* 左上2 */
            95% 0%,    /* 右上1 */
            100% 5%,   /* 右上2 */
            100% 95%,  /* 右下1 */
            95% 100%,  /* 右下2 */
            5% 100%,   /* 左下1 */
            0 95%      /* 左下2 */
        );
}

效果如下:

如果把polygon()每个点在图上描出来,就像下图所示的一样:

如果你想要的斜切口这样的图形,你可以借助在线的clip-path工具CSS clip-path maker来获取,甚至你可以使用类似Sketch的Polygon工具来绘制,然后导出你所需要的图形坐标点。如果你使用的是Sketch导出的坐标点,那么你还需要人肉或借助工具将px转换成%。有关于百分比的计算,我想你知道如何计算。不过我们今天聊的只是斜切口的制作,其他不是我们今天所讨论的范围,如果你自己感兴趣,可以去自己试试。

对于上图所展示的斜切口效果,你会发现这些凹槽并不是完美的45deg。造成这种现象的主要原因是元素本身并不是一个正方形。另外,你想确定你的斜切口的大小,还可以借助一些数学公式来计算,比如勾股定理:

话又说回来,要解决凹槽不是45deg角也不是难事,借助CSS的calc()函数,可以让我们事情变得简单而又是完美。比如,clip-path裁剪一个带20px切角的矩形元素,我们就可以这样写:

.module {
    clip-path: 
        polygon(
            0% 20px,                 
            20px 0%,                 
            calc(100% - 20px) 0%,    
            100% 20px,               
            100% calc(100% - 20px),  
            calc(100% - 20px) 100%,  
            20px 100%,               
            0 calc(100% - 20px)      
        );
}

对于x轴的calc(100% - 20px)y轴的calc(100% - 20px)对应的位置。正如这个示例,如果元素的尺寸是:

事实上calc(100% - 20px)对应的就是calc(400px - 20px),也就是元素的x轴的380px处,同样的y轴的calc(100% - 20px)即是calc(277px - 20px),也就是元素y轴的257px处。这也是为什么这里使用calc()函数,它可以根据元素自身的尺寸,保证你最终得到的斜切角度是完美的45deg

上面示例的代码中,不难发现,20px我们使用了很多次,这样一来,可以借助CSS处理器(比如,Sass,LESS之类),可以声明一个变量,如此一来,你需要修改斜切口的大小时,只需要修改变量的值。到目前为止,CSS自身也具有变量的概念(规范现在称之为CSS自定义属性)。CSS自定义属性的运行也非常的简单,你可以在:root{}下声明一个变量,你也可以在该元素下声明一个变量,然后通过var()函数来调用声明的变量。下面的示例是在元素自身中声明了一个--notchSize的变量:

.module {
    --notchSize: 20px;
    
    clip-path: 
        polygon(
            0% var(--notchSize), 
            var(--notchSize) 0%, 
            calc(100% - var(--notchSize)) 0%, 
            100% var(--notchSize), 
            100% calc(100% - var(--notchSize)), 
            calc(100% - var(--notchSize)) 100%, 
            var(--notchSize) 100%, 
            0% calc(100% - var(--notchSize))
        );
}

如果你从未接触过CSS自定义属性,那么强烈建议你花点时间阅读一下这方面的教程。小站上整理了不少关于CSS自定义属性的教程

使用CSS自定义属性还有一个优势,可以借助其给开发者暴露的 API:**element.style.setProperty('--variableName', variableValue)**进行动态修改CSS自定义属性的值。比如下面的示例,配合input type="range",你拖动input的滑块时,可以看到元素斜切角的变化:

var inp = document.querySelector("input");
var mod = document.querySelector(".module");

inp.addEventListener("input", function() {
    mod.style.setProperty("--notchSize", this.value + "px");
});

最终的效果如下,大家可以亲自体验一把:

封装一个Vue组件

如果你只想实现一个斜切口效果,你已经完成了,而且效果非常的完美。看到这样的一个效果的时候,我在想,我是否可以将这个效果封装成一个Vue组件。那是因为自己最近在学习Vue相关的知识,所以我尝试着使用Vue来完成这个效果的组件。

具体过程不详细描述,先来看组件模板的代码:

<template id="notch">
    <div class="notch" :style="{'--notchSize': changeChildNotchSize}">
        <slot>This is notch module box!</slot>
    </div>
</template>

<div id="app">
    <c-notch :child-notch-size = notchSize></c-notch>
    
    <div class="form">
        <input type="range" min="0" max="50"  v-model="notchSize" @input="change">
    </div>
</div>

对应的JavaScript代码:

Vue.component('c-notch',{
    template: '#notch',
    props: ['childNotchSize'],
    computed: {
        changeChildNotchSize: function () {
            return this.childNotchSize + 'px'
        }
    }

})

let app = new Vue({
    el: '#app',
    data () {
        return {
            notchSize: '20'
        }
    },
    methods: {
        change: function (e) {
            this.notchSize = e.target.value
        }
    }
})

这个组件刚好让我运用到了前面学习的一些理论知识,比如定义Vue组件模板的方式(除了示例上的创建组件模板方式之外,你也可以使用单个文件来创建组件)、Vue组件通讯Vue的插槽等。

最终效果如下:

上述效果也可以在GitHub中VueStudy仓库下获取

VueStudy是自己学习Vue写的一些小示例,如果你对此感兴趣,不仿加入一起玩耍。

总结

使用CSS实现一个元素斜切口效果的方案其实有很多种,这篇文章主要介绍了,如何使用clip-path实现盒子四边带切口的效果,同时为了切口更为完美,借助calc()函数,让切口具有完美的45deg角。为了更好的避免你多次修改切口的宽度值,采用CSS自定义属性来解决这种重复性工作。最后为了能更好的重复使用该效果,借助于Vue,将其封装为Vue的组件。如果大家感兴趣,不仿试试,利用这些技术,实现其他的一些特效。

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/vue/create-notched-boxes-component-with-vue.htmlnike air max 2019 pink