共计 5349 个字符,预计需要花费 14 分钟才能阅读完成。
效果
体验
web component selectweb components polyfill 兼容旧版本浏览器的支持插件
https://www.webcomponents.org…
Web Component 是一系列 web 平台的 API,它们可以允许你创建全新可定制、可重用并且封装的 HTML 标签
定制的组件基于 Web Component 标准构建,可以在现在浏览器上使用,也可以和任意与 HTML 交互的 JavaScript 库和框架配合使用。
它赋予了仅仅使用纯粹的 JS/HTML/CSS 就可以创建可重用组件的能力。如果 HTML 不能满足需求,我们可以创建一个可以满足需求的 Web Component。
源码
(function () {
const selectListDemo = [{name: 'test1', value: 1},
{name: 'test2', value: 2},
{name: 'test3', value: 3}
]
class MidociSelect extends HTMLElement {static get observedAttributes() {return ['acitve-title', 'active-sub-title']
}
constructor() {super()
this.attachShadow({mode: 'open'})
this.shadowRoot.innerHTML = `
<style>
:host{--themeColor:rgb(24,144,255);
box-sizing: border-box;
font-size: 14px;
--borderColor:#eee;
}
.wrapper{
position: relative;
display: inline-flex;
align-items: center;
padding-left: 10px;
width: 95px;
height: 36px;
border: 1px solid var(--borderColor);
color: #333;
border-radius: 2px;
user-select: none;
transition: .3s cubic-bezier(.12, .4, .29, 1.46);
outline:none
}
.wrapper:hover{border: 1px solid var(--themeColor);
transition: .3s cubic-bezier(.12, .4, .29, 1.46);
}
.title{ }
.arrow-out{
position: absolute;
right: 12px;
top: 50%;
transform: translateY(0px) rotateX(0deg);
transition: .3s cubic-bezier(.12, .4, .29, 1.46);
}
.wrapper.flip>.arrow-out{transform: translateY(-3px) rotateX(180deg);
transition: .3s cubic-bezier(.12, .4, .29, 1.46);
}
.arrow{
display: flex;
width: 6px;
height:6px;
border: none;
border-left: 1px solid #333;
border-bottom: 1px solid #333;
transform: translateY(-50%) rotateZ(-45deg);
transition: .3s cubic-bezier(.12, .4, .29, 1.46);
}
.wrapper:hover .arrow{border-left: 1px solid var(--themeColor);
border-bottom: 1px solid var(--themeColor);
transition: .3s cubic-bezier(.12, .4, .29, 1.46);
}
.list{
z-index: 100;
position: absolute;
top: 130%;
left: 0;
background-color: #fff;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
visibility: hidden;
min-width: 100%;
border-radius: 3px;
transform: scale(0);
transform-origin: top;
transition: .3s cubic-bezier(.12, .4, .29, 1.46);
}
.wrapper.flip>.list{
visibility: visible;
transform: scale(1);
transition: .3s cubic-bezier(.12, .4, .29, 1.46);
}
.item{
display: flex;
align-items: center;
padding-left: 10px;
width: 95px;
height: 36px;
color: #333;
border-radius: 2px;
user-select: none;
background-color: #fff;
transition: background-color .3s ease-in-out;
}
.item:hover{background-color: rgba(24,144,255,0.1);
transition: background-color .3s ease-in-out;
}
</style>
<div class="wrapper" tabindex="1">
<span class="title">1</span>
<span class="arrow-out">
<span class="arrow"></span>
</span>
<div class="list" >
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
</div>
</div>
`
this._wrapperDom = null
this._listDom = null
this._titleDom = null
this._list = []
this._arrowFlip = false
this._value = null
this._name = null
}
connectedCallback() {this._wrapperDom = this.shadowRoot.querySelector('.wrapper')
this._listDom = this.shadowRoot.querySelector('.list')
this._titleDom = this.shadowRoot.querySelector('.title')
this.initEvent()
this.list = selectListDemo
}
disconnectedCallback() {this._wrapperDom.removeEventListener('click', this.flipArrow.bind(this))
this._wrapperDom.removeEventListener('blur', this.blurWrapper.bind(this))
this.shadowRoot.querySelectorAll('.item')
.forEach((item, index) => {item.removeEventListener('click', this.change.bind(this, index))
})
}
attributeChangedCallback(attr, oldVal, newVal) {// const attribute = attr.toLowerCase()
// if (attribute === 'descriptions') {// console.log(1)
// this.render(newVal)
// }
}
set list(list) {if (!this.shadowRoot) return
this._list = list
this.render(list)
}
get list() {return this._list}
set value(value) {this._value = value}
get value() {return this._value}
set name(name) {this._name = name}
get name() {return this._name}
initEvent() {this.initArrowEvent()
this.blurWrapper()}
initArrowEvent() {this._wrapperDom.addEventListener('click', this.flipArrow.bind(this))
}
initChangeEvent() {this.shadowRoot.querySelectorAll('.item')
.forEach((item, index) => {item.addEventListener('click', this.change.bind(this, index))
})
}
change(index) {this.changeTitle(this._list, index)
let changeInfo = {
detail: {
value: this._value,
name: this._name
},
bubbles: true
}
let changeEvent = new CustomEvent('change', changeInfo)
this.dispatchEvent(changeEvent)
}
changeTitle(list, index) {this._value = list[index].value
this._name = list[index].name
this._titleDom.innerText = this._name
}
flipArrow() {if (!this._arrowFlip) {this.showList()
} else {this.hideList()
}
}
showList() {
this._arrowFlip = true
this._wrapperDom.classList = 'wrapper flip'
}
hideList() {
this._arrowFlip = false
this._wrapperDom.classList = 'wrapper'
}
blurWrapper() {this._wrapperDom.addEventListener('blur', (event) => {event.stopPropagation()
this.hideList()})
}
render(list) {if (!list instanceof Array) return
let listString = ''
list.forEach((item) => {
listString += `
<div class="item" data-value="${item.value}">${item.name}</div>
`
})
this._listDom.innerHTML = listString
this.changeTitle(list, 0)
this.initChangeEvent()}
}
const FrozenMidociSelect = Object.freeze(MidociSelect);
customElements.define('midoci-select', FrozenMidociSelect);
})()
注意:如果父元素高度太低,需要关闭父元素的 overflow 属性,否则会遮盖 下拉列表
使用
<script type="module" async>
import './MidociSelect.js'
</script>
<midoci-select></midoci-select>
<script>
const list = [{name: '全平台', value: 1},
{name: '东券', value: 2},
{name: '京券', value: 3}
]
window.onload=function(){document.querySelector('midoci-select').list=list
console.log(document.querySelector('midoci-select').value)
console.log(document.querySelector('midoci-select').name)
document.querySelector('midoci-select').addEventListener('change', (event) => {console.log('选中的 value:', event.detail.value)
console.log('选中的 name:', event.detail.name)
})
}
</script>
正文完
发表至:无分类
2019-07-31