• 重写select


    select 模拟

    目前仿写select的方式

    • tableIndex 来使 div(无法获取焦点的元素)来获取元素,这样便可以在失去焦点时,是否将下拉框收回
    • 通过 document的点击,来判断是否点击了当前元素
    • 利用 input 的自带 click/blur 来处理

    ui

    看了这么多实现方式,我更好奇具体有什么实现方式

    ui 实现方式
    heyui document -- click/contextmenu
    iview tableIndex/document
    element-ui document -- mouse
    fish-ui document -- click
    radon-ui window -- click
    mdui document -- click

    开始仿写

    要求

    • 只实现单选
    • 用原生实现,不基于框架
    • 没有使用上述中将下拉框独立出来
    • 只做向下下拉,没有高度不够时,可以向上或向下

    html

    <div class="sc-select-content" data-toggle="false">
        <label for="" class="sc-select--label">下拉框</label>
        <div class="sc-input--item">
            <input id="input" type="text" class="sc-input" readonly autocomplete="off" placeholder="请选择">
            <i class="sc-select-icon"></i>
        </div>
        <div class="sc-select-item">
            <ul class="select-container">
                <li class="select-item select-item--1">1</li>
                <li class="select-item">2</li>
                <li class="select-item">3</li>
                <li class="select-item">4</li>
                <li class="select-item">5</li>
            </ul>
            <div class="arrow"></div>
        </div>
    </div>
    

    css

    * {
        box-sizing: border-box;
    }
    
    *::before,
    *::after {
        box-sizing: border-box;
    }
    
    .sc-select-content {
        position: relative;
        display: inline-block;
         200px;
    }
    
    .sc-input {
         100%;
        height: 38px;
        outline: none;
        padding: 0 15px;
        border-radius: 4px;
        transition: border-color .2s cubic-bezier(.645, .045, .355, 1);
        border: 1px solid #ccc;
        padding-right: 34px;
    }
    .sc-input--item {
        position: relative;
    }
    .sc-select-icon {
        position: absolute;
        right: 8px;
        top: 16px;
        box-sizing: content-box;
        border-right: 10px solid transparent;
        border-left: 10px solid transparent;
        border-top: 10px solid #ccc;
    }
    .sc-select-icon::after {
        content: '';
        position: absolute;
        right: -10px;
        bottom: 2px;
        box-sizing: content-box;
        border-right: 10px solid transparent;
        border-left: 10px solid transparent;
        border-top: 10px solid #fff;
    }
    
    .sc-input:focus {
        border: 1px solid #FF9310;
        /* box-shadow: 0 0 0 2px rgba(255, 197, 37, 1); */
    }
    
    .sc-select-item {
         100%;
        display: none;
    }
    
    .sc-select-item.active {
        display: block;
        visibility: hidden;
        opacity: 0;
        transform: translateY(10px);
        transition: all .3s cubic-bezier(.55,0,.1,1);
    
        position: absolute;
        padding-top: 10px;
    }
    .sc-select-item.active2 {
        visibility: visible;
        opacity: 1;
        transform: translateY(0);
    }
    
    .select-container {
        position: relative;
        padding: 6px 0;
        margin: 0;
        display: flex;
        flex-direction: column;
        border-radius: 4px;
        border: 1px solid #e4e7ed;
        box-shadow: 0 5px 10px rgba(0, 0, 0, .1);
    }
    
    .sc-select-item .arrow {
        position: absolute;
         0;
        height: 0;
        border-color: transparent;
        border-style: solid;
        border- 6px;
        filter: drop-shadow(0 2px 12px rgba(0,0,0,.03));
        top: 6px;
        left: 20px;
        border-bottom-color: #ebeef5;
        border-top- 0;
    }
    .sc-select-item .arrow::after {
        position: absolute;
        display: block;
         0;
        height: 0;
        border-color: transparent;
        border-style: solid;
        content: " ";
        border- 6px;
        top: 1px;
        margin-left: -6px;
        border-bottom-color: #fff;
        border-top- 0;
    }
    
    .select-item {
        padding: 0 15px;
        height: 38px;
        line-height: 38px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        cursor: pointer;
    }
    
    .select-item:hover {
        background-color: #ddd;
    }
    

    *注意 **:

    js

    /**
      * @description: 找到一个符合的parent
      * @param {Note} node 元素 
      * @param {string} className 元素class类名 
      * @return: Node
      */
    function findParent(node, className) {
        let parent = node.parentNode
        while (parent && parent.classList && [].slice.call(parent.classList).indexOf(className) < 0) {
            parent = parent.parentNode
        }
        if (parent && parent.classList && [].slice.call(parent.classList).indexOf(className) > -1) {
            return parent
        }
    }
    
    const Input = document.getElementById('input')
    Input.addEventListener('click', function (e) {
    		const P = findParent(this, 'sc-select-content')
    		const Select = findChild(P, 'sc-select-item')
    		const toggle = P.dataset.toggle
    		if (toggle === 'true') {
    				Select.classList.remove('active2')
    				setTimeout(function () {
    						Select.classList.remove('active')
    						P.dataset.toggle = false
    				}, 100)
    		} else {
    				console.log(22)
    				Select.classList.add('active')
    				setTimeout(function () {
    						Select.classList.add('active2')
    						P.dataset.toggle = true
    				}, 16)
    		}
    }, false)
    Input.addEventListener('blur', function (e) {
    		const that = this
    		const P = findParent(this, 'sc-select-content')
    		const Select = findChild(P, 'sc-select-item')
    		document.addEventListener('click', function (e) {
    				const isP = findParent(e.target, 'sc-select-content') === P
    				if (!isP) {
    						Select.classList.remove('active2')
    						setTimeout(function () {
    								Select.classList.remove('active')
    								// 时间需要与 transition的时间相同为好
    								P.dataset.toggle = false
    						}, 100)
    				}
    		}, false)
    		Select.addEventListener('click', function (e) {
    				if (e.target.tagName.toLowerCase() === 'li') {
    						that.value =  e.target.innerText
    				}
    				Select.classList.remove('active2')
    				setTimeout(function () {
    						Select.classList.remove('active')
    						// 时间需要与 transition的时间相同为好
    						// toggle = false
    						P.dataset.toggle = false
    				}, 100)
    		}, false)
    }, false)
    

    上述方式

    • 虽然很low,很多方法可以提出来,偷个懒,先如此写
    • 点击,打开关闭
    • 主要利用input的focusblur方法
    • document事件放在里面,是为了拿到上面点击的元素
    • 使用data来存储是否打开还是关闭的boolean

    效果图

    总结

    • 虽然实现的很粗糙,但是更多的是为了了解其他ui是如何实现的
    • 有机会再细细优化了
  • 相关阅读:
    golang-cron定时任务
    卡特兰数
    树的直径
    虚拟机之Hyper-V
    tag of loj
    wx.requestSubscribeMessage无法弹窗,显示20001报错?
    nginx日志切割
    小程序首次加载过慢以及点击微信授权不弹出授权框的问题
    外网访问小程序显示网络错误问题以及总是走wx.request里面的fail回调问题
    http转https以及ssl证书配置以及安装
  • 原文地址:https://www.cnblogs.com/sinosaurus/p/11107541.html
Copyright © 2020-2023  润新知