前言
上一个篇章中我们学习基础的框架搭建,并且实现了一个简单的 button
组件,该组件可以在项目中正常使用,那么按照类似的方法可以哦我们呢可以开发其他常用的组件库。
1. icon组件
icon 组件主要用来引用各种图标,在此之前我们需要知道图标是如何引入到我们自己的组件库中的。我们通过@font-face
的 CSS @规则引入图标字体。使用例子如下,需要注意的是字体格式有太多选择(例如:woff 、ttf、svg等等),不幸的是始终没有一个能在所有的浏览器上通用。这意味着我们必须使用多种字体的方案来保持用户跨平台的一致性体验
。
// 定义图标字体
@font-face {
font-family: 'askbob-iconfont';
src: url('fonts/wbs-icon.woff2?t=1566356524042') format('woff2'),
url('fonts/wbs-icon.woff?t=1566356524042') format('woff'),
url('fonts/wbs-icon.ttf?t=1566356524042') format('truetype'),
url('fonts/wbs-icon.svg?t=1566356524042#wbs-iconfont') format('svg');
}
// css引用
[class*='askbob-icon-'],
[class^='askbob-icon-'] {
...
font-family: 'askbob-iconfont' !important;
...
}
ok,在知晓上面图标引用规则的的前提下,我们再来开发icon 组件,首先是 icon.vue
的开发:
// icon.vue
<template>
<i :class="currentClass" :style="styles" @click="click"></i>
</template>
<script>
export default {
name: `askbob-icon`,
props: {
type: String,
color: String,
size: String,
},
computed: {
currentClass() {
return this.type ? `askbob-icon-` + this.type : '';
},
styles() {
let stl = ``;
if (this.color) stl = stl + `color: ${this.color};`;
if (this.size) stl = stl + `font-size: ${this.size}px;`;
return stl;
},
},
methods: {
click(e) {
this.$emit('click', e);
},
},
};
</script>
上述代码中,可以看到icon组件通过透传属性type
控制图标的类型;通过透传属性 color
控制图标的颜色;通过透传属性 size
控制图标的大小。css代码如下,其中 @icon-size
定义了默认的图标大小变量。
// index.less
@import '../style/theme.less';
@font-face {
font-family: 'askbob-iconfont';
src: url('fonts/wbs-icon.woff2?t=1566356524042') format('woff2'),
url('fonts/wbs-icon.woff?t=1566356524042') format('woff'),
url('fonts/wbs-icon.ttf?t=1566356524042') format('truetype'),
url('fonts/wbs-icon.svg?t=1566356524042#wbs-iconfont') format('svg');
}
// 图标变量
@icon-size: 20px;
[class*='askbob-icon-'],
[class^='askbob-icon-'] {
font-family: 'askbob-iconfont' !important;
font-size: @icon-size;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
display: inline-block;
vertical-align: middle;
}
.askbob-icon-setting:before {
content: '\e603';
}
.askbob-icon-close:before {
content: '\e60a';
}
.askbob-icon-back:before {
content: '\e60b';
}
.askbob-icon-right:before {
content: '\e60c';
}
.askbob-icon-left:before {
content: '\e60d';
}
.askbob-icon-up:before {
content: '\e60e';
}
.askbob-icon-down:before {
content: '\e60f';
}
.askbob-icon-subtract:before {
content: '\e612';
}
.askbob-icon-add:before {
content: '\e613';
}
.askbob-icon-circle:before {
content: '\e618';
}
.askbob-icon-help:before {
content: '\e61c';
}
.askbob-icon-wrong:before {
content: '\e61d';
}
.askbob-icon-info:before {
content: '\e61e';
}
.askbob-icon-close-circle:before {
content: '\e61f';
}
.askbob-icon-success:before {
content: '\e620';
}
.askbob-icon-add-circle:before {
content: '\e622';
}
.askbob-icon-subtract-circle:before {
content: '\e623';
}
.askbob-icon-selected:before {
content: '\e626';
}
.askbob-icon-refresh:before {
content: '\e628';
}
.askbob-icon-more:before {
content: '\e629';
}
.askbob-icon-search:before {
content: '\e62a';
}
.askbob-icon-nav-more:before {
content: '\e62b';
}
.askbob-icon-delete:before {
content: '\e62c';
}
.askbob-icon-warning:before {
content: '\e62e';
}
导出icon 组件,新增 index.js
文件:
import Icon from './icon.vue';
export default Icon;
2. 导航栏组件开发
前面的都是相对来说功能单一,简单的组件,此处我们开发一个导航栏组件,导航栏组件是一个相对来说功能较复杂的组件,一般的导航栏包含:返回按钮、标题显示、搜索按钮、分享按钮等小模块,当涉及到如此多的小模块时候,肯定是需要在导航栏组件中设置插槽位置。
如下代码是导航栏组件的代码实现,代码布局整体上可以分为三个模块:
askbob-navbar-left
中通过透传的isBack
参数控制返回按钮的现实和隐藏,通过isLeftContent
控制左侧文字展示或者隐藏;askbob-navbar-title
中通过插槽控标题内容askbob-navbar-right
也是通过具名插槽控制右侧的相关文字或者按钮
// nav-bar.vue
<template>
<div :class="{ [`askbob-navbar`]: true, [`askbob-navbar-border-bottom`]: borderBottom }">
<div :class="`askbob-navbar-left`" role="button">
<div :class="`askbob-navbar-left-icon`" @click="clickBack" v-if="isBack">
<slot name="icon">
<Icon type="back"></Icon>
</slot>
</div>
<div :class="{ [`askbob-navbar-left-content`]: true, ml: !isBack }" @click="leftContentlick" v-if="isLeftContent">
<slot name="leftContent">{{ leftContent }}</slot>
</div>
</div>
<div :class="`askbob-navbar-title`">
<slot></slot>
</div>
<div :class="`askbob-navbar-right`">
<slot name="rightContent"></slot>
</div>
</div>
</template>
<script>
import Icon from '../icon/icon.vue';
export default {
name: `askbob-nav-bar`,
components: {
Icon,
},
props: {
isBack: {
type: Boolean,
default: true,
},
leftContent: {
type: String,
},
borderBottom: {
type: Boolean,
default: false,
},
},
computed: {
isLeftContent() {
return this.$slots.leftContent !== undefined || !!this.leftContent;
},
},
methods: {
clickBack(e) {
this.$emit('leftClick', e);
},
leftContentlick(e) {
this.$emit('leftContentClick', e);
},
}
};
</script>
以下是对应的css代码,其中定义了相关变量参数,例如:@navbar-height
、 @navbar-fill
、 @navbar-font-size
、 @navbar-icon-font-size
等。
// index.less
@import '../style/theme.less';
@import '../style/hairline.less';
// nav bar相关变量
@navbar-height: 44px;
@navbar-fill: #f3f3f3;
@navbar-font-size: 20px;
@navbar-icon-font-size: 15px;
.askbob-navbar {
position: relative;
display: flex;
align-items: center;
height: @navbar-height;
background-color: @navbar-fill;
color: @color-font;
&-left,
&-title,
&-right {
flex: 1;
height: 100%;
display: flex;
align-items: center;
i {
margin-right: @spacing-margin-base;
&:last-child {
margin-right: 0;
}
}
}
&-left {
&-icon {
display: flex;
justify-content: center;
align-items: center;
height: @navbar-height;
width: @navbar-height;
i {
font-size: @navbar-icon-font-size;
// font-weight: bolder;
display: inherit;
}
}
&-content {
height: @navbar-height;
line-height: @navbar-height;
i {
font-size: @navbar-icon-font-size;
// font-weight: bolder;
display: inherit;
}
}
}
&-title {
justify-content: center;
font-size: @navbar-font-size;
white-space: nowrap;
}
&-right {
justify-content: flex-end;
font-size: @navbar-font-size;
margin-right: @spacing-margin-base;
}
// &-border-bottom {
// .hairline('bottom');
// }
.ml {
margin-left: @spacing-margin-base;
}
}