Btn

按钮类型实现

1 .通过设置type为primary、dashed、text、info、success、warning、error创建不同样式的按钮,不设置为默认样式。
2 .预先写好了type==info的css样式,当选择的时候直接加上这个class。
3 .js代码中

type: {
                validator (value) {
                    return oneOf(value, ['default', 'primary', 'dashed', 'text', 'info', 'success', 'warning', 'error']);
                },
                default: 'default'
            },
//props先验证一下传入的值是否在范围内

computed:{
  classes () {
                return [
                    `${prefixCls}`,
//必加上自己的默认样式 mix
                    `${prefixCls}-${this.type}`,
//必加上按钮样式类型,默认是default样式 mix
                    {
                        [`${prefixCls}-long`]: this.long,
//决定是否要让按钮填满父元素 com
 &-long{
        width: 100%;
    }
                        [`${prefixCls}-${this.shape}`]: !!this.shape,
//决定按钮的形状
                        [`${prefixCls}-${this.size}`]: this.size !== 'default',
//决定按钮的大小 
                        [`${prefixCls}-loading`]: this.loading != null && this.loading,
//决定是否显示load的样式
                        [`${prefixCls}-icon-only`]: !this.showSlot && (!!this.icon || !!this.customIcon || this.loading),
                        [`${prefixCls}-ghost`]: this.ghost
//决定是否是幽灵按钮
                    }
                ];
            },
}
//直接返回一个class数组,有必显示的样式,有根据传入的值显示的数据

4 .结论

1 .所有可能出现的情况的样式都是事先写好,根据传入的参数选择要使用哪些样式
2 .注意排列顺序,有的样式是会覆盖的。或者一开始就明确的把属性区分开来.比如ghost的样式可能会覆盖type的样式
3 .mixins文件夹里面会定义一些可以被复用的代码片段,然后components里面的文件会传入特定的参数来使用它定义的函数片段
4 .他的样式没有使用:style在组件里面现场编成的。都是使用预定义好的
5 .

按钮图标以及形状

1 .通过设置icon属性在Button内嵌入一个Icon,或者直接在Button内使用Icon组件。
使用Button的icon属性,图标位置将在最左边,如果需要自定义位置,需使用Icon组件。
通过设置shape属性为circle,可将按钮置为圆的形状。
2 .解读

1 .要实现这个,就必须在button里面使用slot属性,这样才能保证他可以传入别的组件,不然就只能传入字符串,icon也必须是最前写好的。
2 .我们是可以通过想象写出所有的css样式,比如icon在按钮文字的各个方向,但是这样以想还是有很多情况是用户想要的。
3 .要释放出这一部分的自主性让用户自己选择自己想要的效果

3 .第一种,传入一个参数使用左右分布的icon样式

<Icon class="ivu-load-loop" type="ios-loading" v-if="loading"></Icon>
//自定义给你一个loading icon

        <Icon :type="icon" :custom="customIcon" v-if="(icon || customIcon) && !loading"></Icon>
//别的icon就需要传入参数自己选了。

4 .第二种,slot接收外部传入的icon组件
5 .

button跳转

1 .通过设置 to 可以实现点击按钮直接跳转,支持传入 vue-router 对象。设置 replace 则不会保存历史记录。设置 target,会跟 a 标签一样的行为。
2 .实现这个功能其实要使用button的样式,实际渲染出来的确实a标签,其实他是用标签样式替代了js的部分功能

if(this.to.to){
                
                // this.$router.push({path:this.to})
                // window.open('http://localhost:8080/#/help')

                if(this.to.target){
                    // 如果这个有属性的话,先走打开新页面的路径
                    window.open(`http://localhost:8080/#/${this.to.to}`,this.to.target)
                }else{

                    if(this.to.replace){
                        this.$router.replace({path:this.to.to})
                    }else{
                        this.$router.push({path:this.to.to})
                    }   
                }
            }
//我的实现方式是直接用js实现想要的功能,因为你a标签好像不能跳转router路由的部分吧。

3 .不过这个写法还是实现一下吧,看下这种写法
4 .为什么他的to没有在props里面添加验证,所以取得时候也是这样

const {to}=this
//直接从最外层的this取

5 .

渲染成原生的代码

1 .html-type 设置button原生的type,可选值为button、submit、reset

button group实现

1 .

疑惑部分

1 .const {to}=this

1 .为什么这个传的to不走props流程
2 .this是整个组件,但是里面并没有上面props的值,是在this.$attrs里面才有,他是怎么取到的呢
3 .实测添加了props之后,才会把attrs里面的属性转到this上面

2 .v-bind="tagProps" :给原生的div或者a元素传递一个属性,比如href

computed里面直接计算
 return {
                    href:this.to.href,
                    tagtet:this.to.tagtet

               }

3 .class实现

1 .类似于react一个classes的包,满足对应的条件就加一个class进去
classes(){
            return [
                `${pre}`,
                `${pre}-${this.type}`,
                {
                    [`${pre}-long`]:true,
//注意这里只能包一个[]。
//不加就是语法错误了。。

                }
            ]
        }
2 .最后渲染出来的是这样的["red",{red:true}]
3 .这个是vue官网给出的绑定class的数组语法。

4 .mixins语法

1 .一个混入对象可以包含任意组件选项,当组件使用混入对象时,所有混入对象的选项被“混入”进入改组件本身的选项
2 .也就是别的.vue组件所有的script部分都可以写在这里
3 .打印里面的this。都是返回引用组件的this
4 .对象合并:如果mix里面和组件内部的对象重复,采取递归合并,发生冲突时以组件数据优先
5 .相同生命周期函数将会合并为一个数组,而且会先执行混入对象的钩子函数
6 .值位对象的选项,例如methods,components,directives.将被合并为一个对象,如果对象key冲突,取组件对象的key

跳转逻辑

1 .看起来所有的跳转逻辑,不论是组件还是别的a链接,最后都是由js函数实现的,为什么还要在一开始区分什么a标签和button.还要给a标签绑定一堆属性
2 .还是他想用一些a标签的默认样式,或者他html标签的本来特性。有点不理解
3 .

新的css属性

1 .touch-action:manipulation 触摸屏如何操作元素
2 .

源码

1 .按钮

<template>
    <component 
                :is="tagName" 
                v-bind="tagProps"
                @click="handleClick"
                :class="classes" 
                :disabled="disabled"               
                >
        <!-- 决定这个最后渲染出的元素 -->
        <!-- <span v-if="showSlot" ref="slot"><slot ></slot></span> -->
       <slot></slot>
    </component>
</template>
<script>
import mixinsLink from '../../../mixins/link'
import Icon from '@/components/base/icon/icon.vue'

const pre='li-btn'
// 组件样式的前缀,避免重复,这里和.less文件都需要
export default {
    mixins:[mixinsLink,],
    components:{Icon,},
    props:{
        htmlType:{
            type:String,
            default:'div'
        },
        // 设置button原生的type:reset,button,submit

        type:{
            validator(value){
                return ["default","primary",'dashed','text','text','info','success','warning','error'].includes(value)
            },
            // 复杂验证,必须满足这个数组里面的值
            default:'default'
        },
        // btn的类型

        shape:{
            validator(value){
                return ['circle','circle-outline'].includes(value)
            }
        },
        size:{
            validator(value){   
                return ['default','small','large'].includes(value)
            },
        },
        disabled:Boolean,
        long:{
            type:Boolean,
            default:false,
        },
        // 宽度是否要覆盖全部的父级宽度
        ghost:{
            type:Boolean,
            default:false,
        }



    },
    computed:{
        isHerfPattern(){
            if(this.to){
                return true
            }return false
        },
        // 没人使用这个计算属性,他是不会走计算逻辑,依赖的没有发生改变,也不会重新计算

        tagName(){
            if(this.isHerfPattern){
                return 'div'
            }return 'div'
        },
        tagProps(){
            if(this.isHerfPattern){
                return {
                    href:this.linkUrl,
                    tagtet:this.target,
                    // 这两个原生属性会被绑定到上面的最后确定的元素上面
                }
            }else{
                if(this.htmlType){
                    return {
                        type:this.htmlType
                    }
                }
            }
        },
        classes(){
            return [
                `${pre}`,
                `${pre}-${this.type}`,
                {
                    [`${pre}-long`]:this.long,
                    [`${pre}-${this.shape}`]:!!this.shape,
                    // !!a 就是他真实的布尔值
                    [`${pre}-${this.size}`]:this.size!='default'&&this.size!=undefined,
                    [`${pre}-loading`]:this.loading!=null&&this.loading,
                    [`${pre}-icon-only`]:this.showSlot,
                    [`${pre}-ghost`]:this.ghost,       
                }
            ]
        },
        showSlot(){
            if(this.$slots.default.length==1){
                if(this.$slots.default[0].componentOptions&&this.$slots.default[0].componentOptions['tag']=='Icon'&&this.$parent._name!="<BtnG>"){
                    return true
                }
            }
            return false
            
            // 如果父级没有传入任何东西的话,这个就不显示。
        }
    },
    methods:{
        handleClick(event){
            if(this.disabled)return
            this.$emit("click",event)
            console.log("组件内")
            // 向外派发一个事件
            const openInNewWindow=event.ctrlKey||event.metaKey
            
            this.handleCheckClick(event,openInNewWindow)
            // 只要点击就触发混入里面的函数,然后根据传入的参数来判断是否打开新界面
        }
    }
}
</script>
<style lang="less" src="./btnP.less">

</style>

2 .按钮组

<template>
   <div :class="classes">
       <slot></slot>
   </div> 
</template>
<script>
const pre="li-btn-group"
export default {
    name:"btnG",
    props:{
        size:{
            validator(value){
                return ['small',"large",'default'].includes(value)
            }   
        },
        shape:{
            validator(value){
                return ['circle','circle-outline'].includes(value)
            },
            default:"circle"
        },
        vertical:{
            type:Boolean,
            default:true,
        }
    },
    computed:{
        classes(){
            return [
                `${pre}`,
                {
                    [`${pre}-${this.size}`]:!!this.size,
                    [`${pre}-shu-circle`]:this.shape&&this.vertical,
                    [`${pre}-heng-circle`]:this.shape&&!this.vertical,
                    [`${pre}-shu`]:this.vertical,
                    [`${pre}-heng`]:!this.vertical,
                }
            ]
        }
    }
}
</script>
<style lang="less" src="./btnP.less">

</style>

3 .less样式

@name:.li-btn;

// mixins部分,可以被复用的部分
.button-size(@height;@padding;@font-size;@border-radius){
    height:@height;
    padding: @padding;
    font-size: @font-size;
    border-radius: @border-radius;
}
// color
.button-color(@color;@background;@border){
    color:@color;
    background-color:@background;
    border-color:@border;

    
}
.active-btn-color(@color){
    &:focus{
        box-shadow: 0 0 0 2px fade(@color,20%)
    }
}

.btn-color(@color){
    .button-variant(@btn-primary-color, @color, @color);

    &:hover,
    &:active,
    &.active{
        color:@btn-primary-color;
    }
    .active-btn-color(@color)
}

// 聚合一些样式,这里要看实际使用情况决定聚合以及拆分
.button-variant(@color;@background;@border){
    .button-color(@color, @background, @border);

    &:hover{
        .button-color(tint(@color,20%);tint(@background,20%);tint(@border,20%));
    }

    &:active,
    &.active{
        .button-color(shade(@color,5%);shade(@background,5%);shade(@background,5%));
    }

}

.btn(){
    display: inline-flex;
    justify-content: center;
    align-items: center;
    // display: inline-block;

    margin-bottom:0;
    font-weight: @btn-font-weight;
    text-align: center;
    vertical-align: middle;
    touch-action: manipulation;
    cursor: pointer;
    border:1px solid transparent;
    white-space: nowrap;
    line-height: @line-height-base;
    user-select: none;
    .button-size(@btn-height-base;@btn-padding-small;@btn-font-size;@btn-border-radius);

    transition: color @transition-time linear, background-color @transition-time linear, border @transition-time linear, box-shadow @transition-time linear;

    &:active,
    &:focus{
        // 这个&其实是最后使用的地方的前缀
        outline: none;
    }

    &.disabled,
    &[disabled]{
        cursor: @cursor-disabled;
        >*{
            pointer-events: none;
        }
    }

    >.@{css-prefix-iconfont}{
        line-height:@line-height-base;
    }

    &-large{
        .button-size(@btn-height-large, @btn-padding-large, @btn-font-size-large, @btn-border-radius)
    }

    &-small{
        .button-size(@btn-height-small, @btn-padding-small, @btn-font-size-small, @btn-border-radius)
    }

    &-disabled{
        .button-color(@btn-disable-color;@btn-disable-bg;@btn-disable-border)
    }
    &-icon-only{
        width:32px;
        height: 32px;
        border-radius: 50%;
        padding:0px;
    }
    &-icon-only&-small{
    // .li-btn-icon-only .li-btn-small
        .button-size(@btn-height-base;@btn-padding-small-icon;@btn-font-size;@btn-border-radius)
    }

    &-icon-only&-large{
        .button-size(@btn-height-base;@btn-padding-small-icon;@btn-font-size;@btn-border-radius)
    }
    
}
.btn-circle(@btnClassName:li-btn){
    border-radius:@btn-circle-size;

    &.@{btnClassName}-large{
        border-radius:@btn-circle-size-large;
    }

    &.@{btnClassName}-small{
        border-radius:@btn-circle-size-small;
    }
}
.btn-default(){
    .button-variant(@btn-default-color;@btn-default-bg;@btn-default-border);

    &:hover{
        .button-color(tint(@primary-color,20%);white;tint(@primary-color,20%));
    }
    &:active,
    &.active{
        .button-color(shade(@primary-color,5%), white, shade(@primary-color,5%))
    }
    .active-btn-color(@primary-color);
}

.btn-primary() {
    .button-variant(@btn-primary-color; @btn-primary-bg; @primary-color);

    &:hover,
    //&:focus,
    &:active,
    &.active {
        color: @btn-primary-color;
    }
    .active-btn-color(@primary-color);
}


.btn-dashed() {
    .button-variant(@btn-ghost-color, @btn-ghost-bg, @btn-ghost-border);
    border-style: dashed;

    &:hover
    //&:focus
    {
        .button-color(tint(@primary-color, 20%); @btn-ghost-bg; tint(@primary-color, 20%));
    }
    &:active,
    &.active {
        .button-color(shade(@primary-color, 5%); @btn-ghost-bg; shade(@primary-color, 5%));
    }
    .active-btn-color(@primary-color);
}

.btn-ghost(){
    .button-variant(@btn-ghost-color, @btn-ghost-bg, @btn-ghost-border);

    &:hover{
        .button-color(tint(@primary-color,20%);@btn-ghost-bg;tint(@primary-color,20%))
    }

    &:active
    &.active{
        .button-variant(shade(@primary-color,5%), @btn-ghost-bg, shade(@primary-color,5%))
    }

    .active-btn-color(@primary-color)
}

.btn-text() {
    .button-variant(@btn-ghost-color, transparent, transparent);

    // for disabled
    &.disabled,
    &[disabled],
    fieldset[disabled] & {
        &,
        &:hover,
        &:focus,
        &:active,
        &.active {
            .button-color(@btn-disable-color; @btn-ghost-bg; transparent);
        }
    }

    &:hover
        //&:focus
    {
        .button-color(tint(@primary-color, 20%); @btn-ghost-bg; transparent);
    }
    &:active,
    &.active {
        .button-color(shade(@primary-color, 5%); @btn-ghost-bg; transparent);
    }
    .active-btn-color(@primary-color);
}

.btn-base(){
    display: inline-flex;
}



// 真正里面的使用
@{name}{
    .btn;
    .btn-default;

    >span{
        display: inline-block;
        box-sizing: border-box;
        vertical-align: middle;
    }

    &-long{
        width:100%;
    }
    // primary的样式
    &-primary{
        .btn-primary;
    }
    &-dashed{
        .btn-dashed;
    }
    &-text{
        .btn-text;
    }
    // 这三个都是和样式有关的变化情况

    &-success{
        .btn-color(@success-color)
    }

    &-warning{
        .btn-color(@warning-color)
    }

    &-error{
        .btn-color(@error-color)
    }
    &-info{
        .btn-color(@info-color)
    }

    &-loading{
        pointer-events: none;
        position: relative;
    }

    &-ghost{
        color:#fff;
        background: transparent;
        &:hover{
            background: transparent;
        }
    }
    &-ghost&-dashed,&-ghost-default{
        color:#fff;
        border-color:#fff;
        &:hover{
            color:tint(@primary-color,20%);
            border-color:tint(@primary-color,20%)
        }
    }
    &-ghost&-primary{
        color:@primary-color;
        &:hover{
            color:tint(@primary-color,20%);
            background:fade(tint(@primary-color,95%),50%);
        }
    }
    &-ghost&-info{
        color:@info-color;
        &:hover{
            color:tint(@info-color,20%);
            background: fade(tint(@info-color,95%),50%);
        }
    }

    &-ghost&-success{
        color:@success-color;
        &:hover{
            color:tint(@success-color,20%);
            background:fade(tint(@success-color,95%),50%)
        }
    }
    &-ghost&-warning{
        color:@warning-color;
        &:hover{
            color:tint(@warning-color,20%);
            background:fade(tint(@warning-color,95%),50%)
        }
    }
    &-ghost&-error{
        color:@error-color;
        &:hover{
            color:tint(@error-color,20%);
            background:fade(tint(@error-color,95%),50%)
        }
    }
    &-ghost&-default[disabled], &-ghost&-dashed[disabled], &-ghost&-primary[disabled], &-ghost&-info[disabled], &-ghost&-success[disabled], &-ghost&-warning[disabled], &-ghost&-error[disabled]{
        background: transparent;
        color: fade(#000, 25%);
        border-color: @btn-disable-border;
    }
    &-ghost-text[disabled]{
        background: transparent;
        color:fade(#000,25%)
    }

    &-circle,&-ciecle-outline{
        .btn-circle(@name)
    }

    > .li-icon{
        padding: 0px 5px;
    }

  


    // 组样式
    &-group{
       
        &-heng{
            .btn-base;
            & div:first-child{
                border-bottom-left-radius: 10%;
                border-top-left-radius: 10%;

            }
            & div:last-child{
                border-bottom-right-radius: 10%;
                border-top-right-radius: 10%;
            }

            & div{
                border-radius:0;
                &:hover{
                    z-index:2;
                    // 竟然在这里
                }
            }

            & div:not(:first-child){
            margin-left:-1px;
            }

            &-circle{
                & div:first-child{
                    border-bottom-left-radius: 50%;
                    border-top-left-radius: 50%;
    
                }
                & div:last-child{
                    border-bottom-right-radius: 50%;
                    border-top-right-radius: 0%;
                }
            }
        }

        &-shu{
            display: inline-flex;
            flex-direction: column;

            & div:first-child{
                border-top-right-radius: 10%;
                border-top-left-radius: 10%;
        
            }
            & div:last-child{
                border-bottom-right-radius: 10%;
                border-bottom-left-radius: 10%;
            }
        
            & div{
                border-radius:0;
                &:hover{
                    z-index:2;
                    // 竟然在这里
                }
            }
        
            & div:not(:first-child){
               margin-top:-1px;
            }

            &-circle{
                & div:first-child{
                    border-top-right-radius: 50%;
                    border-top-left-radius: 50%;
            
                }
                & div:last-child{
                    border-bottom-right-radius: 50%;
                    border-bottom-left-radius: 50%;
                }
            }
         
        }
    }
    
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容

  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,381评论 0 17
  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,480评论 1 11
  • 《牧羊少年奇幻之旅》里有这样一段话:在人生的某个时候,我们失去了对自己生活的掌控,命运主宰了我们的人生。这就是世上...
    桃子爱读书阅读 791评论 0 4
  • 白浅下意识看向怀中人,竟是孙子辈最疼爱的孩子,白凤九。此时的凤九早已没了气息,满身是血的倒在白浅怀里。衣服有...
    笙笙不息白笙阅读 4,389评论 2 45
  • 1、明确金钱对自己的意义。 (1)让钱成为生活中一种令人愉快的力量; (2)大多数人的最终愿望就是让自己更加幸福、...
    我是婷玉呀阅读 225评论 2 6