实现一个类继承HTMLElement
class MRadio extends HTMLElement {
// 如果子类重写了constructor,则必须调用父类的构造函数 spuer()
constructor () {
super()
}
}
// 注册自定义组件
customElements.define('mt-radio',MRadio)
创建影子DOM
init () {
let shadow = this.attachShadow({
mode: 'open' // 指定为开放的封装模式
})
}
组件 - 数据部分
this.state = {}
try {
this.state.data = JSON.parse(this.getAttribute('data'))
this.state.index = this.getAttribute('index') || 0
} catch (error) {
this.state.data = []
this.state.index = 0
}
组件 - 事件部分
// 因为DOM元素设置成开放模式所以获取dom的根结点需要用this.shadowRoot
event () {
this.shadowRoot.addEventListener('click', e => {
if(e.target.tagName.toUpperCase() == 'LI'){
this.state.index = e.target.dataset.n
this._render()
}
})
}
组件 - 样式部分
style () {
let style = document.createElement('style')
style.textContent = `
.box{
margin:100px auto 0;
width: 80%;
}
.clear:after{
content: '';
display: block;
clear: both;
}
.radio{
list-style: none;
display: inline-block;
margin: 0;
padding: 0;
}
.radio .item{
float: left;
padding: 12px 25px;
margin-left: 1px;
height: 30px;
border: 1px solid
background:
text-align: center;
font-size: 16px;
line-height: 30px;
transition: .2s all;
cursor: pointer;
}
.radio .item:hover{
box-shadow: inset 0 0 130px
color:
}
.radio .item:first-child{
border-radius: 5px 0 0 5px;
}
.radio .item:last-child{
border-radius: 0 5px 5px 0;
}
.radio .item.checked{
box-shadow: inset 0 0 130px
color:
}
`
this.shadowRoot.appendChild(style)
}
组件 - 结构部分
html () {
let container = document.createElement('div')
container.classList.add('box')
this.shadowRoot.appendChild(container)
this._render()
}
_render () {
let container = this.shadowRoot.querySelector('div.box')
container.innerHTML = this.render()
}
render () {
let str = this.state.data.map((item,n) => {
if (n == this.state.index) {
return `<li class="item checked" data-n=${n}>${item}</li>`
} else {
return `<li class="item" data-n=${n}>${item}</li>`
}
}).join('')
return `<ul class="radio clear">${str}</ul>`
}
完整的代码
<body>
<mt-radio data='["北京","上海","广州","深圳"]' index=0></mt-radio>
<mt-radio data='["前端","后端"]' index=1></mt-radio>
</body>
<script>
class MRadio extends HTMLElement {
// 如果子类重写了constructor,则必须调用父类的构造函数 spuer()
constructor () {
super()
this.init()
}
// 创建影子DOM
init () {
let shadow = this.attachShadow({
mode: 'open'
})
// 获取数据
this.data()
// 注册事件
this.event()
// 设置样式
this.style()
// 生成DOM元素
this.html()
}
data () {
this.state = {}
try {
this.state.data = JSON.parse(this.getAttribute('data'))
this.state.index = this.getAttribute('index') || 0
} catch (error) {
this.state.data = []
this.state.index = 0
}
}
event () {
this.shadowRoot.addEventListener('click', e => {
if(e.target.tagName.toUpperCase() == 'LI'){
this.state.index = e.target.dataset.n
this._render()
}
})
}
style () {
let style = document.createElement('style')
style.textContent = `
.box{
margin:100px auto 0;
width: 80%;
}
.clear:after{
content: '';
display: block;
clear: both;
}
.radio{
list-style: none;
display: inline-block;
margin: 0;
padding: 0;
}
.radio .item{
float: left;
padding: 12px 25px;
margin-left: 1px;
height: 30px;
border: 1px solid
background:
text-align: center;
font-size: 16px;
line-height: 30px;
transition: .2s all;
cursor: pointer;
}
.radio .item:hover{
box-shadow: inset 0 0 130px
color:
}
.radio .item:first-child{
border-radius: 5px 0 0 5px;
}
.radio .item:last-child{
border-radius: 0 5px 5px 0;
}
.radio .item.checked{
box-shadow: inset 0 0 130px
color:
}
`
this.shadowRoot.appendChild(style)
}
html () {
let container = document.createElement('div')
container.classList.add('box')
this.shadowRoot.appendChild(container)
this._render()
}
_render () {
let container = this.shadowRoot.querySelector('div.box')
container.innerHTML = this.render()
}
render () {
let str = this.state.data.map((item,n) => {
if (n == this.state.index) {
return `<li class="item checked" data-n=${n}>${item}</li>`
} else {
return `<li class="item" data-n=${n}>${item}</li>`
}
}).join('')
return `<ul class="radio clear">${str}</ul>`
}
}
customElements.define('mt-radio',MRadio)
</script>