前端实现表格下拉框筛选和表头回显和删除
前言
公司项目要实现在表格上通过表头添加筛选条件,筛选后再表格上方回显筛选后的数据可单独删除和全部删除。 效果如下:
实现思路
下拉筛选
- 传递的给后端的数据为单个值时(如多选地区等):使用v-model双向绑定来传递数据
- 传递的给后端的数据为两个值时(如时间段筛选 开始时间-结束时间等):使用v-bind传递数组来进行获取和设置
表头筛选条件
- 通过下拉筛选改变的值所组装的数据来进行回显
- 在表格组件里面传递所有传递给后端的值一个对象用来改变传递的数据
代码实现
下拉筛选代码
<template>
<div class="dropDownFilter-container">
<el-dropdown class="elDropdownBox" ref="dropDownFilterElDropDownRef" trigger="click" :hide-on-click="false" @visible-change="visibleChange">
<div class="titleBox" ref="dropDownFilterTitleBoxRef">
<div class="title">{{ title }}</div>
<div class="titleIcon">
<i class="iconfont iconBox" :class="[isFiltered?'icon-yishaixuan':'icon-sangedian']"></i>
</div>
</div>
<el-dropdown-menu slot="dropdown" placement="bottom-end">
<el-dropdown-item class="elDropContainer">
<!--单个 日期选择器 -->
<template v-if="['date','dateYear','dateMonth'].includes(type)">
<el-date-picker v-model="internalValue" :format="dateFormat" :value-format="dateFormat" :type="dateType" placeholder="选择日期" @change="dateChange" :popper-class="className">
</el-date-picker>
</template>
<!-- 日期时间范围选择器 -->
<template v-if="['dateRange','dateRangeMonth','dateRangeTime'].includes(type)">
<el-date-picker v-model="internalValue" :format="dateRangeFormat" :value-format="dateRangeFormat" :type="dateRangeType" @change="dateRangeChange" :append-to-body="false" range-separator="~" start-placeholder="开始日期" end-placeholder="结束日期" :clearable="false" :popper-class="className">
</el-date-picker>
</template>
<!-- 多选复选框 -->
<template v-if="type === 'checkbox'">
<div class="searchBox">
<el-input v-model="searchValue" placeholder="请输入内容"></el-input>
</div>
<div class="container">
<el-checkbox-group v-model="checkValue" @change="checkChange">
<div class="checkboxBox">
<div v-for="item in selectOptions" :key="item[optValue]" class="checkItem">
<el-checkbox :label="item[optValue]">{{item[optLabel]}}</el-checkbox>
</div>
</div>
</el-checkbox-group>
</div>
</template>
<!-- 省市区 父子关联 -->
<template v-if="type ==='area'">
<el-cascader v-model="areaValue" ref="areaCascadredropDownFilterRef" placeholder="请选择" :options="areaList" @change="areaChange" :props="{label:optLabel,value:optValue,children:optChildren,multiple:true}" :append-to-body="false" :show-all-levels="false" clearable size="mini" collapse-tags></el-cascader>
</template>
<!-- 多级选择器 -->
<template v-if="type ==='cascader'">
<el-cascader v-model="areaValue" ref="cascadredropDownFilterRef" placeholder="请选择" :options="selectOptions" @change="cascaderChange" :props="{label:optLabel,value:optValue,children:optChildren,multiple:true}" :append-to-body="false" :popper-class="className" :show-all-levels="false" clearable size="mini" collapse-tags></el-cascader>
</template>
<!-- 输入框范围 -->
<template v-if="type ==='inputRange'">
<div class="inpitRangeBox">
<div class="iColBox">
<el-input v-model.number.trim="minNum" placeholder="请输入最小值" class="focusVisibleOutLine" style="width: 110px"></el-input>
<span class="iline" style="margin: 0 5px">—</span>
<el-input v-model.number.trim="maxNum" placeholder="请输入最大值" class="focusVisibleOutLine" style="width: 110px"></el-input>
</div>
<div class="tipBox" v-if="tipText">{{ tipText }}</div>
<div class="inBtnBox">
<span class="clearBtn" @click="clearInputRange">清空</span>
<el-button size="mini" type="primary" @click="inputRangeChange">确定</el-button>
</div>
</div>
</template>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<script>
/**
* 下拉框组件
*
* 使用方法: 配合headerFilter使用,headerFilter是表头筛选条件组件
*
* @type: 类型
*
* 1.单个日期选择器------date 日 dateMonth 月 dateYear 年
* 2.日期范围选择器------dateRange 日 dateRangeTime 时分秒 dateRangeMonth 月
* 3.复选框-------------checkbox
* 4.省市区选择器--------area
* 5.多级选择器---------cascader
* 6.输入框范围选择器----inputRange
*
*
* 1.单个日期选择器
* <DropDownFilter type="date" title="日期" v-model="reqParams.dateData" valueKey="dateData" @dropDownFilterChange="dropDownFilterChange" />
* 2.日期范围选择器
* <DropDownFilter type="dateRange" title="时间" :valueKey="['startSubmitTime','endSubmitTime']" :params="reqParams" @dropDownFilterChange="dropDownFilterChange" />
* 3.复选框
* <DropDownFilter type="checkbox" title="来源" v-model="reqParams.source" valueKey="source" :options="aOpt" optLabel="dictName" optValue="dictCode" @dropDownFilterChange="dropDownFilterChange" />
* 4.省市区选择器
* <DropDownFilter type="area" title="地区" v-model="reqParams.cityList" valueKey="cityList" optValue="id" optChildren="children" @dropDownFilterChange="dropDownFilterChange" />
* 5.多级选择器
* <DropDownFilter type="cascader" title="国标行业" v-model="reqParams.industryList" valueKey="industryList" :options="industryNameIdList" optValue="id" @dropDownFilterChange="dropDownFilterChange" />
* 6.输入框范围选择器
* <DropDownFilter type="inputRange" title="积分" :valueKey="['pointsCountStart','pointsCountEnd']" :params="reqParams" @dropDownFilterChange="dropDownFilterChange" />
*
*
* // 下拉筛选改变触发
dropDownFilterChange(params, assembleData) {
this.selectedFilters = this.selectedFilters.filter(item => item.title !== assembleData.title);
if (assembleData.value) {
this.selectedFilters.push(assembleData);
}
// 自己的逻辑
// this.reqParams.startIndex = 1
// this.getPageList()
}
属性
* @valueKey 选中值key 如果是单个日期选择器,则传字符串 ,如果是日期范围选择器,则传数组
* @params 对象参数
* @options 下拉框选项
* @optLabel 下拉框选项名字key
* @optValue 下拉框选项vakue-key
* @optChildren 下拉框选项子级key
*
* 方法
* @dropDownFilterChange 下拉筛选改变触发
*
*
*/
import { getCityTree } from '@/api/common'
export default {
props: {
// 类型
type: {
type: String,
default: ''
},
// 标题
title: {
type: String,
default: ''
},
// 选中值key 如果是单个日期选择器,则传字符串 ,如果是日期范围选择器,则传数组
valueKey: {
type: [String, Array],
default: ''
},
// v-model双向绑定
value: {
type: [String, Array, Number, Object],
default: ''
},
// 下拉框选项
options: {
type: Array,
default: () => []
},
// 下拉框选项名字key
optLabel: {
type: String,
default: 'label'
},
// 下拉框选项vakue-key
optValue: {
type: String,
default: 'value'
},
// 下拉框选项子级key
optChildren: {
type: String,
default: 'children'
},
// 对象参数
params: {
type: Object,
default: () => { }
},
// 下拉框选项是否右对齐
isPopperRight: {
type: Boolean,
default: false
}
},
data() {
return {
className: '',
// 多选框选中的数据
checkValue: [],
// 单项选择选中的数据
internalValue: '',
// 搜索框
searchValue: '',
// 下拉框选项
selectOptions: [],
// 地区数据
areaList: [],
areaValue: [],
// 选择后回显的名字
selectNameList: [],
minNum: '',
maxNum: '',
tipText: '',
// 是否被筛选
isFiltered: false
}
},
watch: {
// 监听下拉框选项数据
options: {
handler(val) {
this.selectOptions = val
},
immediate: true,
deep: true
},
// v-model双向绑定
value: {
handler(val) {
let typeS = this.type
if (!val || val.length == 0) {
this.isFiltered = false
}
if (typeS == 'checkbox') {
this.checkValue = val
} else if (typeS == 'area' || typeS == 'cascader') {
if (val.length == 0) {
this.areaValue = []
this.isFiltered = false
}
} else {
this.internalValue = val
}
},
deep: true,
},
// 监听 headerFilter表头筛选删除触发清空已选的数据
params: {
handler(val) {
if (['dateRange', 'dateRangeMonth', 'dateRangeTime'].includes(this.type)) {
if (!val[this.valueKey[0]]) {
this.internalValue = ''
this.isFiltered = false
}
}
if (this.type == 'inputRange') {
if (!val[this.valueKey[0]]) {
this.internalValue = ''
this.minNum = ''
this.maxNum = ''
this.isFiltered = false
}
}
},
deep: true,
}
},
computed: {
// 时间格式转换
dateFormat() {
switch (this.type) {
case 'date':
return 'yyyy-MM-dd'
case 'dateYear':
return 'yyyy'
case 'dateMonth':
return 'yyyy-MM'
}
},
// 时间类型转换
dateType() {
switch (this.type) {
case 'date':
return 'date'
case 'dateYear':
return 'year'
case 'dateMonth':
return 'month'
}
},
// 时间范围格式转换
dateRangeFormat() {
switch (this.type) {
case 'dateRange':
return 'yyyy-MM-dd'
case 'dateRangeMonth':
return 'yyyy-MM'
case 'dateRangeTime':
return 'yyyy-MM-dd HH:mm:ss'
}
},
// 时间范围类型转换
dateRangeType() {
switch (this.type) {
case 'dateRange':
return 'daterange'
case 'dateRangeMonth':
return 'monthrange'
case 'dateRangeTime':
return 'datetimerange'
}
}
},
mounted() {
if (this.type === 'area') {
this.getAreaList()
}
this.getElementPostion()
},
methods: {
// 输入框点击清除按钮触发
clearInputRange() {
this.minNum = ''
this.maxNum = ''
},
// 输入框点击确定按钮触发
inputRangeChange() {
if (!this.minNum && !this.maxNum) {
this.tipText = '请输入最小值或最大值'
return
}
if (this.minNum && this.maxNum && this.minNum > this.maxNum) {
this.tipText = '最小值不能大于最大值'
return
}
this.tipText = ''
if (this.valueKey && this.valueKey.length == 2) {
this.params[this.valueKey[0]] = this.minNum
this.params[this.valueKey[1]] = this.maxNum
}
this.internalValue = [this.minNum, this.maxNum]
this.selectNameList = this.internalValue
this.visibleChange(false);
this.triggerChange()
},
// 多级选择器选择触发
cascaderChange() {
let list = this.$refs['cascadredropDownFilterRef'].getCheckedNodes()
list = list.filter(item => !(item.parent && item.parent.checked))
this.internalValue = list.map(v => v.value)
this.selectNameList = list.map(v => v.label)
this.triggerChange()
},
// 地区选择触发
areaChange(val) {
let list = this.$refs['areaCascadredropDownFilterRef'].getCheckedNodes()
list = list.filter(item => !(item.parent && item.parent.checked))
this.internalValue = list.map(v => v.value)
this.selectNameList = list.map(v => v.label)
this.triggerChange()
},
// 复选框选择触发
checkChange(val) {
this.internalValue = val
this.selectNameList = this.getSelectName()
this.triggerChange()
},
// 时间选择器触发
dateRangeChange(val) {
for (let i = 0; i < this.valueKey.length; i++) {
this.params[this.valueKey[i]] = val[i]
}
this.selectNameList = this.internalValue
this.visibleChange(false);
this.triggerChange()
},
// 时间选择器触发
dateChange(val) {
this.selectNameList = [val]
this.visibleChange(false);
this.triggerChange()
},
// 获取选中的名字
getSelectName() {
let selectName = []
if (this.checkValue.length) {
for (let i = 0; i < this.checkValue.length; i++) {
let item = this.selectOptions.find(v => v[this.optValue] == this.checkValue[i])
selectName.push(item)
}
}
selectName = selectName.map(v => v[this.optLabel])
return selectName
},
// 选择完成后触发
triggerChange() {
this.$emit('input', this.internalValue)
// 获取当前选中值
let dataKeyMap = {}
// 组装数据
let assembleData = {
// 类型
type: this.type,
// 标题
title: this.title,
// 选中的值
value: {},
// 当前的key
key: this.valueKey,
// 选中的名字
nameList: this.selectNameList,
}
// 根据类型组装数据
if (Array.isArray(this.valueKey)) {
for (let i = 0; i < this.valueKey.length; i++) {
dataKeyMap[this.valueKey[i]] = this.internalValue[i]
}
assembleData.value = dataKeyMap
} else {
dataKeyMap = { [this.valueKey]: this.internalValue }
assembleData.value = dataKeyMap[this.valueKey]
}
this.isFiltered = true
// console.log(assembleData, 'assembleData');
this.$emit('dropDownFilterChange', dataKeyMap, assembleData)
},
// 下拉框显示隐藏
visibleChange(val) {
if (!val) {
this.$refs.dropDownFilterElDropDownRef.hide();
}
},
// 获取地区列表
getAreaList() {
getCityTree().then(res => {
if (res.code == 0) {
this.areaList = res.data
}
})
},
// 获取当前元素所在位置来判断下拉是在左开还是右开
getElementPostion() {
let el = this.$refs.dropDownFilterTitleBoxRef
if (el) {
let elLeft = el.getBoundingClientRect().left
let sceenWidth = window.innerWidth
if (sceenWidth - elLeft < 400) {
this.className = 'elDropDownFilterPopstionRight'
}
}
if (this.isPopperRight && (this.type == 'area' || this.type == 'cascader')) {
this.className = 'elDropDownFilterPopstionRight'
}
}
}
}
</script>
<style>
.elDropDownFilterPopstionRight {
right: 0 !important;
left: auto !important;
}
</style>
<style lang="scss" scoped>
.inpitRangeBox,
.iline,
.tipBox,
.clearBtn,
.focusVisibleOutLine {
&:focus,
&:focus-visible {
outline: unset;
}
&:hover {
background: #fff;
}
}
.el-dropdown-menu__item:focus,
.dropDownFilter-container {
width: 100%;
&:focus,
&:focus-visible {
outline: unset;
}
.elDropdownBox {
width: 100%;
.titleBox {
display: flex;
align-items: center;
justify-content: space-between;
&:focus,
&:focus-visible {
outline: unset;
}
.iconBox {
cursor: pointer;
}
}
}
}
.elDropContainer {
// all: unset;
padding: 0px 10px !important;
border-radius: 4px;
&:hover {
background: #fff;
}
.container {
width: 264px;
.checkboxBox {
.checkItem {
width: 100%;
line-height: 30px;
height: 30px;
font-size: 12px;
&:hover {
background: #edecf0;
}
}
}
}
.inpitRangeBox {
padding: 10px 0;
position: relative;
.tipBox {
font-size: 12px;
color: red;
position: absolute;
line-height: 16px;
}
.inBtnBox {
margin-top: 10px;
display: flex;
justify-content: flex-end;
align-items: center;
.clearBtn {
margin-right: 10px;
color: #0052cc;
}
}
}
}
</style>
表头筛选代码
<template>
<div class="headerFilter-container" v-if="selectData.length">
<div class="container">
<span>表头筛选条件:</span>
<div class="switchBox">
<i class="el-icon el-icon-caret-left"></i>
</div>
<div class="rowBox">
<div class="colBox" v-for="item in selectData" :key="item.title">
<div class="left">
<div class="name"> {{ item.title }}:</div>
<div class="value">
<template v-if="['dateRange','inputRange','dateRangeMonth','dateRangeTime'].includes(item.type) ">
{{ item.nameList.join('~') }}
</template>
<template v-else>
{{ item.nameList.join(',') }}
</template>
</div>
</div>
<div class="iconBox" @click="removeFilter(item)">
<i class="el-icon-close"></i>
</div>
</div>
</div>
<div class="switchBox">
<i class="el-icon el-icon-caret-right"></i>
</div>
<div class="blueText mt4 cura" @click="clearAll">清除全部</div>
</div>
</div>
</template>
<script>
/**
* 表头筛选条件组件
*
* 使用方法:配合dropDownFilter组件使用
*
* <HeaderFilter :option="selectedFilters" :params="reqParams" @change="headerChange" />
*
* // 表头筛选改变触发
headerChange(val, data) {
for (const key in val) {
this.reqParams[key] = val[key]
}
this.selectedFilters = data
// 自己的逻辑
// this.reqParams.startIndex = 1
// this.getPageList()
}
// 下拉筛选改变触发
dropDownFilterChange(params, assembleData) {
this.selectedFilters = this.selectedFilters.filter(item => item.title !== assembleData.title);
if (assembleData.value) {
this.selectedFilters.push(assembleData);
}
// 自己的逻辑
// this.reqParams.startIndex = 1
// this.getPageList()
}
属性
@option 筛选条件数组
@params 请求参数
方法
@change 筛选条件改变触发
*/
export default {
props: {
option: {
type: Array,
default: () => []
},
params: {
type: Object,
default: () => { }
}
},
data() {
return {
selectData: this.option
}
},
watch: {
option: {
handler(val) {
if (val && val.length) {
this.selectData = val.filter(v => v.nameList && v.nameList.length)
}
},
immediate: true,
deep: true
}
},
methods: {
// 点击清除全部按钮
clearAll() {
for (let i = 0; i < this.selectData.length; i++) {
this.changeData(this.selectData[i])
}
this.selectData = []
this.$emit('change', this.params, [])
},
// 点击删除按钮
removeFilter(item) {
let index = this.selectData.findIndex((i) => i.title === item.title)
if (index !== -1) {
this.changeData(item)
this.selectData.splice(index, 1)
this.$emit('change', this.params, this.selectData)
}
},
// 改变数据
changeData(item) {
if (Array.isArray(item.value)) {
this.params[item.key] = []
} else if (typeof item.value === 'string') {
this.params[item.key] = ''
} else {
for (const key in item.value) {
this.params[key] = ''
}
}
}
}
}
</script>
<style lang="scss" scoped>
.headerFilter-container {
.container {
display: flex;
align-items: center;
.rowBox {
display: flex;
align-items: center;
gap: 10px;
.colBox {
width: 230px;
padding: 0 10px;
height: 24px;
line-height: 24px;
background-color: #f2f5f9;
border-radius: 4px;
display: flex;
align-items: center;
font-size: 12px;
overflow: hidden;
.left {
flex: 1;
flex-shrink: 0;
display: flex;
align-items: center;
overflow: hidden;
.name {
white-space: nowrap;
}
.value {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.iconBox {
width: 16px;
margin-left: 6px;
cursor: pointer;
}
}
}
.switchBox {
width: 20px;
height: 24px;
line-height: 24px;
margin: 0 10px;
cursor: pointer;
background-color: #fff;
text-align: center;
.el-icon-caret-left {
color: #172b4d;
}
}
}
}
</style>
使用
- 在表格页面分别引用这两个组件
- import HeaderFilter from '@/components/headerFilter/index.vue'
- import DropDownFilter from '@/components/dropDownFilter/index.vue'
<template>
<div style="padding: 20px;">
<!-- 表头筛选选择项 -->
<div class="headBox" v-if="selectedFilters.length">
<HeaderFilter :option="selectedFilters" :params="reqParams" @change="headerChange" />
</div>
<!-- 表格 -->
<el-table :data="tableData">
<el-table-column prop="address">
<template #header>
<DropDownFilter v-model="reqParams.cityList" title="地区1" valueKey="cityList" type="area" optValue="id" optChildren="children" @dropDownFilterChange="dropDownFilterChange" />
</template>
</el-table-column>
<el-table-column prop="date">
<template #header>
<DropDownFilter type="date" title="日期" valueKey="dateData" v-model="reqParams.dateData" @dropDownFilterChange="dropDownFilterChange" />
</template>
</el-table-column>
<el-table-column prop="date">
<template #header>
<DropDownFilter title="年份" valueKey="year" type="dateYear" v-model="reqParams.year" @dropDownFilterChange="dropDownFilterChange" />
</template>
</el-table-column>
<el-table-column prop="date">
<template #header>
<DropDownFilter title="月份" valueKey="month" type="dateMonth" v-model="reqParams.month" @dropDownFilterChange="dropDownFilterChange" />
</template>
</el-table-column>
<el-table-column>
<template #header>
<DropDownFilter type="dateRange" title="时间" :valueKey="['startSubmitTime','endSubmitTime']" :params="reqParams" @dropDownFilterChange="dropDownFilterChange" />
</template>
</el-table-column>
<el-table-column>
<template #header>
<DropDownFilter type="dateRangeMonth" title="时间月份" :valueKey="['startYear','endYear']" :params="reqParams" @dropDownFilterChange="dropDownFilterChange" />
</template>
</el-table-column>
<el-table-column>
<template #header>
<DropDownFilter type="dateRangeTime" title="时间分钟" :valueKey="['startRanTime','endRanTime']" :params="reqParams" @dropDownFilterChange="dropDownFilterChange" />
</template>
</el-table-column>
<el-table-column prop="name">
<template #header>
<DropDownFilter type="inputRange" title="积分" :valueKey="['pointsCountStart','pointsCountEnd']" :params="reqParams" @dropDownFilterChange="dropDownFilterChange" />
</template>
</el-table-column>
<el-table-column prop="address">
<template #header>
<DropDownFilter type="cascader" title="地区" v-model="reqParams.cityList1" isPopperRight valueKey="cityList1" :options="industryNameIdList" optValue="id" @dropDownFilterChange="dropDownFilterChange" />
</template>
</el-table-column>
<el-table-column prop="address">
<template #header>
<DropDownFilter type="dateRange" title="提交时间" :valueKey="['startTime','endTime']" :params="reqParams" @dropDownFilterChange="dropDownFilterChange" />
</template>
</el-table-column>
<el-table-column prop="address">
<template #header>
<DropDownFilter v-model="reqParams.address" title="地址" valueKey="address" type="checkbox" :options="aOpt" optLabel="dictName" optValue="dictCode" @dropDownFilterChange="dropDownFilterChange" />
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import Drag from './drag.vue'
import NoPower from '@/components/noPower/index.vue'
import { getDictList } from '@/api/common.js'
import HeaderFilter from '@/components/headerFilter/index.vue'
import DropDownFilter from '@/components/dropDownFilter/index.vue'
import { findIndustryList } from '@/api/user.js'
export default {
components: {
NoPower,
DropDownFilter,
HeaderFilter,
Drag
},
data() {
return {
selectedFilters: [],
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}],
reqParams: {
startRanTime: '',
endRanTime: '',
startYear: '',
endYear: '',
month: '',
year: '',
pointsCountStart: '',
pointsCountEnd: '',
cityList1: [],
cityList: [],
startTime: '',
endTime: '',
dateData: [],
userName: '',
address: [],
startSubmitTime: '',
endSubmitTime: '',
startIndex: 1,
pageSize: 10
},
nameOpt: [{
label: '张三',
value: 'zhangsan'
},
{
label: '李四',
value: 'lisi'
},
{
label: '王五',
value: 'wangwu'
}],
aOpt: [],
industryNameIdList: []
}
},
mounted() {
this.getInit()
},
methods: {
// 表头筛选改变触发
headerChange(val, data) {
for (const key in val) {
this.reqParams[key] = val[key]
}
this.selectedFilters = data
this.reqParams.startIndex = 1
},
// 下拉筛选改变触发
dropDownFilterChange(params, assembleData) {
this.selectedFilters = this.selectedFilters.filter(item => item.title !== assembleData.title);
if (assembleData.value) {
this.selectedFilters.push(assembleData);
}
// 自己的逻辑
this.reqParams.startIndex = 1
},
handleClick() {
console.log(this.reqParams);
},
getInit() {
getDictList('info_source').then(res => {
if (res.code == 0) {
this.aOpt = res.data
}
})
// 查询国标行业
findIndustryList().then(res => {
this.industryNameIdList = res.data
})
}
}
}
</script>
<style>
.headBox {
padding-bottom: 20px;
}
</style>