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. jquery last 选择器 语法

    jquery last 选择器 语法 作用: :last 选择器选取最后一个元素.最常见的用法:与其他元素一起使用,选取指定组合中的最后一个元素(就像上面的例子). 语法:$(":last& ...

  2. sh_11_九九乘法表

    sh_11_九九乘法表 # 1. 打印 9 行小星星 row = 1 while row <= 9: col = 1 while col <= row: # print("*&q ...

  3. 随堂小测APP使用体验

    随堂小测APP使用体验 先要去注册账号需要填写用户名.密码.手机号.学号/教师号.学校.专业.即可注册,注册成功后,即可登录APP进,登陆进去以后.会有两个界面,课堂和我的,注册.登录简单,通俗易懂, ...

  4. (61)C语言预处理命令详解

    一  前言 预处理(或称预编译)是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作.预处理指令指示在程序正式编译前就由编译器进行的操作,可放在程序中任何位置. 预处理是C语言的一个重要功能 ...

  5. Jmeter -- 参数化(函数助手和CSV数据文件配置)

    使用场景: 例如:模拟多用户登陆时 参数化两种方式: 方式一:使用函数助手 1. 创建包含多个登录名和密码的文件 可以在文本编辑器中输入,格式如下: username,passwordusername ...

  6. excel里面匹配部分字符的问题

                如上图所示,有两个表,前者存的是区号电话号连起来的电话号,后者存的是世界各地的区号,怎么把第一个表里分成两列,一列单独存区号,一列单独存电话号. ps:电话号码长度和区号长度都 ...

  7. 使用jdk自带的visualVM监控远程监控was

    1.登录was控制台https://172.16.87.221:9043/ibm/console/unsecureLogon.jsp服务器--服务器类型--Java 和进程管理---进程定义---Ja ...

  8. md5值校验

    使用哈希的md5给文件加指纹,如果文件被更改,指纹信息就会不匹配,从而确定文件的原值是否被改动. [root@b test]# md5sum a.txt > zhiwen.txt[root@b ...

  9. 516D Drazil and Morning Exercise

    分析 求出直径和最远距离d 之后我们以直径中点为根 发现父亲的d肯定不小于儿子的d 于是从下往上启发式合并维护与子树根的值相差L内的个数即可 代码 #include<bits/stdc++.h& ...

  10. Linux_系统进程管理

    目录 目录 进程管理 进程管理的指令 查看进程ps指令 pgreppidof指令查pid lsof查看系统中的进程 nice指令修改进程的nice值 kill指令结束进程 top系统进程管理器任务管理 ...