一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
我年纪轻轻就被老大喊到办公室:你要加油哦,要快快滴熟悉业务和公司框架,以后当个大佬。那一瞬间,我哭辽,太感动了。就问问你们,这样的信任,你们敢想吗?于是,我打算封装两个小组件,方便以后接手公司框架。我可是要当公司架构师的人。我对自己加油鼓励。
声明下:这篇文章是vue组件学习的笔记,记载了一些封装思路。而想自己动手试试的,需要有相关前置技能:懂vue,懂个锤子的那种就行
正文
1.明确需求
明确button按钮的功能需求,参照element可知:
1.1· 文字可变,
1.2· 按钮状态可变,
1.3· 鼠标移上去会有效果,
1.4· 按钮种类有:朴素,炫彩,拟态,圆角,停用,icon
1.5· 点击事件
2.正式开始
2.1 - 在 components文件夹内创建文件--button.vue。并在button.vue内给上
name:QButton,我们不单独创建css的样式文件。这一点和element不太一样。
<template>
<button class="q-button">
按钮组件
</button>
</template>
<script>
export default {
name: 'QButton'
}
</script>
<style lang="scss">
</style>
2.2-这个时候,我们需要在main.js里面全局注册button组件,
import QButton from '../components/button.vue'
Vue.component(QButton.name,QButton)
然后在APP.vue中使用,
<template>
<div id="app">
<div class="button">
<div class="row">
<h3>普通按钮</h3>
<q-button></q-button>
</div>
</div>
</template>
2.3 - 在文件创建好并全局注册后,写入页面骨架及样式,
<template>
<button
class='q-button'
>
嘤嘤嘤
</button>
</template>
<style lang="scss">
.q-button{
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #ffffff;
border: 1px solid #dcdfe6;
color: #606266;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: 0.1s;
font-weight: 500;
//禁止元素的文字被选中
-moz-user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
&:hover,
&:hover{
color: #409eff;
border-color: #c6e2ff;
background-color: #ecf5ff;
}
}
</style>
2.4-接下来我们开始实现button功能 2.3-1:实现文字可控,
//app.vue中传入'可可爱爱'
<template>
<div id="app">
<div class="row" >
<h3>普通按钮</h3>
<QButton>普通按钮</QButton>
<QButton>普通按钮</QButton>
<QButton>普通按钮</QButton>
</div>
</div>
</template>
// button组件中
<button class="q-button">
<!-- tip:根据是否传入内容进行span渲染 -->
<span v-if="$slots.default">
<slot></slot>// solt,让app传入的文字在这显示
</span>
</button>
效果展示:
2.3-2:实现按钮状态可变,
type
颜色可变我们通过css类名控制,通过type传来的状态进行切换颜色
//app.vue中传入'可可爱爱'
<template>
<div id="app">
<div class="row" >
<h3>状态按钮</h3>
<QButton type="default">default按钮</QButton>
<QButton type="success">success按钮</QButton>
<QButton type="primary">primary按钮</QButton>
<QButton type="danger">danger按钮</QButton>
<QButton type="warning">warning按钮</QButton>
<QButton type="info">info按钮</QButton>
</div>
</div>
</template>
// button组件中
<template>
<button
:class="[
'q-button',
`q-button--${type}`, // 动态为class绑定不同类名
]"
>
<!-- tip:根据是否传入内容进行span渲染 -->
<span v-if="$slots.default">
<slot></slot>
</span>
</button>
</template>
<script>
export default {
name: 'QButton',
data() {
return {}
},
components: {},
props: {
// 按钮类型
type: {
type: String,
default: 'default',
// type值校验
validator: function(value) {
return (
[
'default',
'success',
'primary',
'danger',
'warning',
'info'
].indexOf(value) !== -1
)
}
},
}
}
<style lang="scss">
.q-button--primary {
color: #fff;
backgrounq-color: $primary-color;
border-color: $primary-color;
// box-shadow: inset 3px 6px 10px #337ecc, inset -3px -7px 10px #4dbeff;
&:hover,
&:focus {
background: $normal-active-color;
backgrounq-color: $normal-active-color;
color: #fff;
}
}
.q-button--success {
color: #fff;
backgrounq-color: $success-color;
border-color: $success-color;
&:hover,
&:focus {
background: $success-active-color;
backgrounq-color: $success-active-color;
color: #fff;
}
}
.q-button--info {
color: #fff;
backgrounq-color: $info-color;
border-color: $info-color;
&:hover,
&:focus {
background: $info-active-color;
backgrounq-color: $info-active-color;
color: #fff;
}
}
.q-button--warning {
color: #fff;
backgrounq-color: $warning-color;
border-color: $warning-color;
&:hover,
&:focus {
background: $warning-active-color;
backgrounq-color: $warning-active-color;
color: #fff;
}
}
.q-button--danger {
color: #fff;
backgrounq-color: $danger-color;
border-color: $danger-color;
&:hover,
&:focus {
background: $danger-active-color;
backgrounq-color: $danger-active-color;
color: #fff;
}
}
</style>
效果展示:
2.3-3:实现朴素按钮,plain
朴素按钮和状态按钮一样,都是通过改变类名而改变
//app.vue中传入'可可爱爱'
<template>
<div id="app">
<div class="button">
<div class="row">
<h3>朴素按钮</h3>
<QButton type="default" plain>default按钮</QButton>
<QButton type="success" plain>success按钮</QButton>
<QButton type="primary" plain>primary按钮</QButton>
<QButton type="danger" plain>danger按钮</QButton>
<QButton type="warning" plain>warning按钮</QButton>
<QButton type="info" plain>info按钮</QButton>
</div>
</div>
</div>
</template>
// button组件中
<template>
<button
:class="[
'q-button',
`q-button--${type}`, // 动态为class绑定不同类名
plain ? 'is-plain' : '',//朴素按钮
]"
>
<!-- tip:根据是否传入内容进行span渲染 -->
<span v-if="$slots.default">
<slot></slot>
</span>
</button>
</template>
<script>
export default {
name: 'QButton',
data() {
return {}
},
components: {},
props: {
// 朴素按钮
plain: {
type: Boolean
},
}
}
<style lang="scss">
// 朴素按钮
.q-button.is-plain {
box-shadow: unset;
&:hover,
&:focus {
background: #fff;
border-color: #489eff;
color: #409eff;
}
}
.q-button--primary.is-plain {
box-shadow: unset;
color: #409eff;
background: #ecf5ff;
&:hover,
&:focus {
background: #409eff;
border-color: #409eff;
color: #fff;
}
}
.q-button--success.is-plain {
box-shadow: unset;
color: #67c23a;
background: #c2e7b0;
&:hover,
&:focus {
background: #67c23a;
border-color: #67c23a;
color: #fff;
}
}
.q-button--info.is-plain {
box-shadow: unset;
color: #909399;
background: #d3d4d6;
&:hover,
&:focus {
background: #909399;
border-color: #909399;
color: #fff;
}
}
.q-button--warning.is-plain {
box-shadow: unset;
color: #e6a23c;
background: #f5dab1;
&:hover,
&:focus {
background: #e6a23c;
border-color: #e6a23c;
color: #fff;
}
}
.q-button--danger.is-plain {
box-shadow: unset;
color: #f56c6c;
background: #fbc4c4;
&:hover,
&:focus {
background: #f56c6c;
border-color: #f56c6c;
color: #fff;
}
}
<style>
效果展示:
2.3-4:实现拟态按钮,mimicry
自己diy的拟态样式
//app.vue中传入'可可爱爱'
<template>
<div id="app">
<div class="row">
<h3>拟态按钮</h3>
<QButton type="default" mimicry>default按钮</QButton>
<QButton type="success" mimicry>success按钮</QButton>
<QButton type="primary" mimicry>primary按钮</QButton>
<QButton type="danger" mimicry>danger按钮</QButton>
<QButton type="warning" mimicry>warning按钮</QButton>
<QButton type="info" mimicry>info按钮</QButton>
</div>
</div>
</template>
// button组件中
<template>
<button
:class="[
'q-button',
`q-button--${type}`, // 动态为class绑定不同类名
plain ? 'is-plain' : '',//朴素按钮
mimicry ? 'is-mimicry' : '',// 拟态按钮
]"
>
<!-- tip:根据是否传入内容进行span渲染 -->
<span v-if="$slots.default">
<slot></slot>
</span>
</button>
</template>
<script>
export default {
name: 'QButton',
data() {
return {}
},
components: {},
props: {
// 拟态按钮
mimicry: {
type: Boolean,
default: false
},
}
}
<style lang="scss">
// 拟态
.q-button.is-mimicry {
box-shadow: inset 3px 6px 10px #ccc, inset -3px -7px 10px #fff;
}
.q-button--primary.is-mimicry {
box-shadow: inset 3px 6px 10px #337ecc, inset -3px -7px 10px #4dbeff;
}
.q-button--info.is-mimicry {
box-shadow: inset 3px 6px 10px #73767a, inset -3px -7px 10px #adb0b8;
}
.q-button--success.is-mimicry {
box-shadow: inset 3px 6px 10px #6aa54e, inset -3px -7px 10px #a0f774;
}
.q-button--warning.is-mimicry {
box-shadow: inset 3px 6px 10px #bc914f, inset -3px -7px 10px #ffd977;
}
.q-button--danger.is-mimicry {
box-shadow: inset 3px 6px 10px #c45656, inset -3px -7px 10px #ff8282;
}
<style>
效果展示:
2.3-5:实现圆角按钮-round,圆形按钮-circle,及停用按钮-disabled
//app.vue中传入'可可爱爱'
<template>
<div id="app">
<div class="row">
<h3>圆角按钮</h3>
<QButton type="default" round>default按钮</QButton>
<QButton type="success" round>success按钮</QButton>
<QButton type="primary" round>primary按钮</QButton>
<QButton type="danger" round>danger按钮</QButton>
<QButton type="warning" round>warning按钮</QButton>
<QButton type="info" round>info按钮</QButton>
</div>
<div class="row row42px">
<h3>圆形按钮</h3>
<QButton type="default" circle >🦅</QButton>
<QButton type="success" circle>🦅</QButton>
<QButton type="primary" circle >🦅</QButton>
<QButton type="danger" circle >🦅</QButton>
<QButton type="warning" circle >🦅</QButton>
<QButton type="info" circle >🦅</QButton>
</div>
<div class="row">
<h3>禁用按钮</h3>
<QButton type="default" disabled >default按钮</QButton>
<QButton type="success" disabled >success按钮</QButton>
<QButton type="primary" disabled >primary按钮</QButton>
<QButton type="danger" disabled >danger按钮</QButton>
<QButton type="warning" disabled >warning按钮</QButton>
<QButton type="info" disabled >info按钮</QButton>
</div>
</div>
</template>
// button组件中
<template>
<button
:class="[
'q-button',
`q-button--${type}`, // 动态为class绑定不同类名
plain ? 'is-plain' : '',//朴素按钮
mimicry ? 'is-mimicry' : '',// 拟态按钮
round ? 'is-round' : '',//圆角按钮
circle ? 'is-circle' :'',//圆形按钮
disabled ? 'is-disabled' : ''//禁用按钮
]"
>
<!-- tip:根据是否传入内容进行span渲染 -->
<span v-if="$slots.default">
<slot></slot>
</span>
</button>
</template>
<script>
export default {
name: 'QButton',
data() {
return {}
},
components: {},
props: {
// round圆角按钮
round: {
type: Boolean
},
// 圆形按钮
circle: {
type: Boolean
},
// disabled禁用
disabled: {
type: Boolean,
default: false
}
}
}
<style lang="scss">
// 让图标和文字之间空开
.q-button [class*='fa-'] + span {
margin-left: 5px;
}
// round圆角按钮
.q-button.is-round {
border-radius: 20px;
padding: 12px 23px;
}
// 圆形按钮
.q-button.is-circle {
border-radius: 50%;
padding: 12px;
}
// 禁用
.q-button.q-button.is-disabled .mask {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(148, 146, 146, 0.39);
left: 0;
top: 0;
box-shadow: 2px 2px 3px rgba(216, 213, 213, 0.3);
border-radius: 4px;
z-index: 100;
}
.q-button.is-round .mask {
border-radius: 20px;
}
.q-button.is-circle .mask {
border-radius: 50%;
}
.q-button.is-disabled {
cursor: no-drop;
}
$normal-color: #fff;
$normal-active-color: #409eff;
$primary-color: #409eff;
$primary-active-color: #66b1ff;
$info-color: #909399;
$info-active-color: #a6a9ad;
$success-color: #67c23a;
$success-active-color: #85ce61;
$warning-color: #e6a23c;
$warning-active-color: #ebb563;
$danger-color: #f56c6c;
$danger-active-color: #f78989;
<style>
效果展示:
2.3-6:实现图标icon
在项目中使用字体图标,首先需要有字体图标,我们可以去阿里巴巴矢量图标库下载。
下载完成后,在asset目录下新建一个fonts目录,存放我们下载到的字体图标。
在main.js中引入字体图标
import './assets/fonts/iconfont.css'
下载的字体图标css文件中的类名做修改,我将icon全部改为了q-icon,并且将初始的iconfont类改为了[class*='q-icon'],当类名中有q-icon时使用,如下
[class*='q-icon'] {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.q-icon-bluetoothoff:before {
content: "\e697";
}
接下来就是老样子了
//app.vue中传入'可可爱爱'
<template>
<div id="app">
<div class="row row42px">
<h3>实现icon</h3>
<QButton type="default" circle icon="yanjing"></QButton>
<QButton type="success" circle icon="guanbi"></QButton>
<QButton type="primary" circle icon="huanyipi"></QButton>
<QButton type="danger" circle icon="search"></QButton>
<QButton type="warning" circle icon="app4"></QButton>
<QButton type="info" circle icon="Aa"></QButton>
</div>
</div>
</template>
// button组件中
<template>
<button
:class="[
'q-button',
`q-button--${type}`, // 动态为class绑定不同类名
plain ? 'is-plain' : '',//朴素按钮
mimicry ? 'is-mimicry' : '',// 拟态按钮
round ? 'is-round' : '',//圆角按钮
circle ? 'is-circle' :'',//圆形按钮
disabled ? 'is-disabled' : ''//禁用按钮
]"
>
<fai :icon="icon" v-if="icon" /> // icon的渲染
<!-- tip:根据是否传入内容进行span渲染 -->
<span v-if="$slots.default">
<slot></slot>
</span>
</button>
</template>
<script>
export default {
name: 'QButton',
data() {
return {}
},
components: {},
props: {
// icon
icon: {
// tip:这里icon为数组类型,给它添加一个布尔作为默认值,让fai不渲染
type: [Array, Boolean],
default: false
},
}
}
<style lang="scss">
// 让图标和文字之间空开
.q-button [class*='fa-'] + span {
margin-left: 5px;
}
效果展示:
2.3-7:实现点击方法
我们在使用组件时,直接给组件定义事件是不会被触发的。我们需要在组件中定义一个点击事件,这个点击事件不进行其他操作,只触发父组件中的点击事件
定义点击事件
<template>
<button class="q-button" :class="[`q-button-${type}`,{
'is-plain':plain,
'is-round':round,
'is-circle':circle,
}]"
@click="handleClick"
>
<i v-if="icon" :class="`q-icon-${icon}`"></i>
<!-- 如果没传入文本插槽,则不显示span内容 -->
<span v-if="$slots.default"><slot></slot></span>
</button>
</template>
<script>
export default {
name: 'QButton',
data() {
return {}
},
components: {},
methods: {
//定义一个点击事件,这个点击事件的作用是调用父组件中的点击事件,并且回调
handleClick (e) {
this.$emit('click', e)
}
}
props: {
// icon
icon: {
// tip:这里icon为数组类型,给它添加一个布尔作为默认值,让fai不渲染
type: [Array, Boolean],
default: false
},
}
}
</script>
//APP父组件
<div class="row row42px">
<h3>实现点击事件</h3>
<QButton type="default" circle icon="yanjing" @click="handClickButton"></QButton>
</div>
methods: {
handClickButton(e) {
console.log(e, '大傻逼')
}
}
效果展示:
2.3-8:突发奇想加个玻璃态
<template>
<button
:class="[
'q-button',
`q-button--${type}`,
mimicry ? 'is-mimicry' : '',
plain ? 'is-plain' : '',
round ? 'is-round' : '',
circle ? 'is-circle' : '',
disabled ? 'is-disabled' : '',
glass ? 'is-glass' : '',//玻璃态
]"
:disabled="disabled"
@click="handleClick"
>
<i v-if="icon" :class="`q-icon-${icon}`"></i>
<!-- 如果没传入文本插槽,则不显示span内容 -->
<span v-if="$slots.default"><slot></slot></span>
</button>
</template>
// props内再传个参
props: {
// 玻璃态
glass: {
type: Boolean,
default: false
}
}
<style>
// 玻璃态按钮
.q-button.is-glass {
background-color: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(10px);
}
</style>
效果展示:
Last:成型板button组件完整代码
<template>
<button
:class="[
'q-button',
`q-button--${type}`,
mimicry ? 'is-mimicry' : '',
plain ? 'is-plain' : '',
round ? 'is-round' : '',
circle ? 'is-circle' : '',
disabled ? 'is-disabled' : '',
glass ? 'is-glass' : '',
]"
:disabled="disabled"
@click="handleClick"
>
<i v-if="icon" :class="`q-icon-${icon}`"></i>
<!-- 如果没传入文本插槽,则不显示span内容 -->
<span v-if="$slots.default"><slot></slot></span>
</button>
</template>
<script>
export default {
name: 'QButton',
data() {
return {}
},
methods: {
handleClick(e) {
this.$emit('click', e)
}
},
components: {},
props: {
// 按钮类型
type: {
type: String,
default: 'default',
// type值校验
validator: function (value) {
return (
[
'default',
'success',
'primary',
'danger',
'warning',
'info'
].indexOf(value) !== -1
)
}
},
// 拟态
mimicry: {
type: Boolean,
default: false
},
// 朴素按钮
plain: {
type: Boolean
},
// round按钮
round: {
type: Boolean
},
// 圆形按钮
circle: {
type: Boolean
},
// icon
icon: {
type: String,
default: ''
},
// disabled禁用
disabled: {
type: Boolean,
default: false
},
// 玻璃态
glass: {
type: Boolean,
default: false
}
},
created() {},
mounted() {},
computed: {},
watched: {}
}
</script>
<style scoped lang="scss">
$normal-color: #fff;
$normal-active-color: #409eff;
$primary-color: #409eff;
$primary-active-color: #66b1ff;
$info-color: #909399;
$info-active-color: #a6a9ad;
$success-color: #67c23a;
$success-active-color: #85ce61;
$warning-color: #e6a23c;
$warning-active-color: #ebb563;
$danger-color: #f56c6c;
$danger-active-color: #f78989;
.q-button {
display: inline-block;
position: relative;
font-family: "PingFang SC", "Microsoft Yahei", sans-serif;
line-height: 1;
cursor: pointer;
background-color: $normal-color;
border: 1px solid #dcdfe6;
white-space: nowrap;
color: #606266;
box-sizing: border-box;
outline: none;
transition: 0.1s;
font-weight: 500;
// 禁止文字被选中
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
&:hover,
&:focus {
color: $normal-active-color;
border-color: #c6e2ff;
background-color: #ecf5ff;
}
}
.q-button--primary {
color: #fff;
background-color: $primary-color;
border-color: $primary-color;
// box-shadow: inset 3px 6px 10px #337ecc, inset -3px -7px 10px #4dbeff;
&:hover,
&:focus {
background: $normal-active-color;
background-color: $normal-active-color;
color: #fff;
}
}
.q-button--success {
color: #fff;
background-color: $success-color;
border-color: $success-color;
&:hover,
&:focus {
background: $success-active-color;
background-color: $success-active-color;
color: #fff;
}
}
.q-button--info {
color: #fff;
background-color: $info-color;
border-color: $info-color;
&:hover,
&:focus {
background: $info-active-color;
background-color: $info-active-color;
color: #fff;
}
}
.q-button--warning {
color: #fff;
background-color: $warning-color;
border-color: $warning-color;
&:hover,
&:focus {
background: $warning-active-color;
background-color: $warning-active-color;
color: #fff;
}
}
.q-button--danger {
color: #fff;
background-color: $danger-color;
border-color: $danger-color;
&:hover,
&:focus {
background: $danger-active-color;
background-color: $danger-active-color;
color: #fff;
}
}
// 拟态
.q-button.is-mimicry {
box-shadow: inset 3px 6px 10px #ccc, inset -3px -7px 10px #fff;
}
.q-button--primary.is-mimicry {
box-shadow: inset 3px 6px 10px #337ecc, inset -3px -7px 10px #4dbeff;
}
.q-button--info.is-mimicry {
box-shadow: inset 3px 6px 10px #73767a, inset -3px -7px 10px #adb0b8;
}
.q-button--success.is-mimicry {
box-shadow: inset 3px 6px 10px #6aa54e, inset -3px -7px 10px #a0f774;
}
.q-button--warning.is-mimicry {
box-shadow: inset 3px 6px 10px #bc914f, inset -3px -7px 10px #ffd977;
}
.q-button--danger.is-mimicry {
box-shadow: inset 3px 6px 10px #c45656, inset -3px -7px 10px #ff8282;
}
// 朴素按钮
.q-button.is-plain {
box-shadow: unset;
&:hover,
&:focus {
background: #fff;
border-color: #489eff;
color: #409eff;
}
}
.q-button--primary.is-plain {
box-shadow: unset;
color: #409eff;
background: #ecf5ff;
&:hover,
&:focus {
background: #409eff;
border-color: #409eff;
color: #fff;
}
}
.q-button--success.is-plain {
box-shadow: unset;
color: #67c23a;
background: #c2e7b0;
&:hover,
&:focus {
background: #67c23a;
border-color: #67c23a;
color: #fff;
}
}
.q-button--info.is-plain {
box-shadow: unset;
color: #909399;
background: #d3d4d6;
&:hover,
&:focus {
background: #909399;
border-color: #909399;
color: #fff;
}
}
.q-button--warning.is-plain {
box-shadow: unset;
color: #e6a23c;
background: #f5dab1;
&:hover,
&:focus {
background: #e6a23c;
border-color: #e6a23c;
color: #fff;
}
}
.q-button--danger.is-plain {
box-shadow: unset;
color: #f56c6c;
background: #fbc4c4;
&:hover,
&:focus {
background: #f56c6c;
border-color: #f56c6c;
color: #fff;
}
}
// round圆角按钮
.q-button.is-round {
border-radius: 20px;
padding: 12px 23px;
}
// 圆形按钮
.q-button.is-circle {
border-radius: 50%;
padding: 12px;
}
// 玻璃态按钮
.q-button.is-glass {
background-color: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(10px);
}
// 让图标和文字之间空开
.q-button [class*="q-"] + span {
margin-left: 5px;
}
// 禁用
.q-button.q-button.is-disabled .mask {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(148, 146, 146, 0.39);
left: 0;
top: 0;
box-shadow: 2px 2px 3px rgba(216, 213, 213, 0.3);
border-radius: 4px;
z-index: 100;
}
.q-button.is-round .mask {
border-radius: 20px;
}
.q-button.is-circle .mask {
border-radius: 50%;
}
.q-button.is-disabled {
cursor: no-drop;
}
</style>
喜欢的话,请给个三连,因为真是穷的没电脑用。