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;
width: 200px;
} .sc-input {
width: 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 {
width: 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;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
filter: drop-shadow(0 2px 12px rgba(0,0,0,.03));
top: 6px;
left: 20px;
border-bottom-color: #ebeef5;
border-top-width: 0;
}
.sc-select-item .arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
content: " ";
border-width: 6px;
top: 1px;
margin-left: -6px;
border-bottom-color: #fff;
border-top-width: 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是如何实现的
  • 有机会再细细优化了

重写select的更多相关文章

  1. 重写select样式

    select {/*Chrome和Firefox里面的边框是不一样的,所以复写了一下*/border: solid 1px #000; /*很关键:将默认的select选择框样式清除*/appeara ...

  2. 自定义属性的时候,尽量不要使用value这个命名

    最近我在重写select下拉组件时,使用ul->li来模拟select中的一个个option,并给li添加索引,取名为value. 非IE浏览器下value值工作正常,但是IE下value值工作 ...

  3. 关于TCP连接建立与终止那点事

    0. 前言 最近在处理公司遗留项目的时候发现自己对TCP协议一点都不懂,所以补了点关于TCP连接的建立和终止的内容,这里简单写下自己了解的部分,省略了报文序号确认序号这些无关的字段,主要讨论TCP状态 ...

  4. ASP.NET Aries 高级开发教程:使用存储过程(番外篇)

    前言: 发现这个问题,有不少人提起过,所以就简单写成文章吧. 接下来看如何在Aries 框架中使用存储过程,整体步骤和绑定普通视图差不多. 步骤一:新建一个空视图. 可以在SqlCode管理中,创建一 ...

  5. 3.2 Zend_Db_Select

    10.4. Zend_Db_Select 你能够使用该对象和它的对应方法构建一个select查询语句,然后生成 字符串符用来传送给zend_db_adapter进行查询或者读取结果. 你也能够在你的查 ...

  6. RocketMQ学习笔记(9)----RocketMQ的Producer 顺序消息

    1. 顺序消息原理图 2. 什么是顺序消息? 消费消息的顺序要求同发送消息的顺序一致,在RocketMQ中,主要指的是局部顺序,即一类消息为满足顺序性,必须Producer单线程顺序发送,并且发送给到 ...

  7. 【转帖】从 Oracle 到 PostgreSQL ,某保险公司迁移实践 技术实践

    从 Oracle 到 PostgreSQL ,某保险公司迁移实践 http://www.itpub.net/2019/11/08/4108/ 信泰人寿保险股份有限公司 摘要:去O一直是金融保险行业永恒 ...

  8. 【Oracle】SQL/92 执行多个表的连接

    内连接 外连接 自连接 交叉连接 1.内连接 表名 INNER JOIN 表名 ON 条件 等价于: FROM 表名, 表名 WHERE 条件 SELECT p.name, pt.name, pt.p ...

  9. Rocket Mq 常用API 及简单运维

    RocketMQ 常用API 消息 消息消费模式 消息消费模式由消费者来决定,可以由消费者设置MessageModel来决定消息模式. 消息模式默认为集群消费模式 consumer.setMessag ...

随机推荐

  1. Windows+anaconda+jupyter notebook+R+python3.6

    Windows+anaconda+jupyter notebook+R+python3.6 环境配置 1. 设置国内清华大学镜像 打开 anaconda prompt,输入命令 conda confi ...

  2. 【canvas学习笔记四】绘制文字

    本节我们来学习如何绘制文字. 绘制文字有两个主要的方法: fillText(text, x, y [, maxWidth]) 在x, y位置填充文字text,有一个可选参数maxWidth设置最大绘制 ...

  3. wordcloud:让你的词语像云朵一样美

    介绍   对文本中出现频率较高的关键词给予视觉化的显示 使用 python import jieba import codecs import wordcloud file = r"C:\U ...

  4. AttributeError: module 'datetime' has no attribute 'now'

    在用时间转化时,一直报AttributeError: module 'datetime' has no attribute 'now', 我用的 import datetime   datetime ...

  5. 南京网络赛C

    分段打表大法好!!! 打表40min,A题1s https://nanti.jisuanke.com/t/41300 #include<bits/stdc++.h> #define int ...

  6. [BZOJ2427]:[HAOI2010]软件安装(塔尖+DP)

    题目传送门 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用${W}_{i}$的磁盘空间,它的价值为${V}_{i}$.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件 ...

  7. i++ 是线程安全的吗

    相信很多中高级的 Java 面试者都遇到过这个问题,很多对这个不是很清楚的肯定是一脸蒙逼.内心肯定还在质疑,i++ 居然还有线程安全问题?只能说自己了解的不够多,自己的水平有限. 先来看下面的示例来验 ...

  8. python 不灭

    进程与线程的区别? 1进程是CPU资源分配的最小单元,线程是CPU计算的最小单元. 2一个进程中可以有多个线程 3对于python来说,它的进程与线程与其它语言有差异,它是有GIL锁,保证同一进程中, ...

  9. qemu-kvm: unable to map backing store for guest RAM: Cannot allocate memory

    当给 KVM 虚拟机设置 hugepage 时,需要在虚拟机的配置文件里加上下面一段: <memoryBacking> <hugepages/></memoryBacki ...

  10. 省市区,级联查询,ajaxgird,ajaxfrom

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...