各种例子
字符串操作
统计多种字符串
cloud.tencent.com/developer/a…
JS符号【问号点(?.)和双问号(??)的用法】
数组去空+去重
js方法去除数组中的空值
splice方法
/*
方法一:splice方法
缺点:不适用字符串中包含空格
如:array = [1, 2, 3, ' '],调用该方法,结果:[1, 2, 3, ' ']
*/
var array = [1, 2, 3, '']
console.log(trimSpace(array)); //打印结果: [1, 2, 3]
function trimSpace(array) {
for (var i = 0; i < array.length; i++) {
if (array[i] == "" || array[i] == null || typeof (array[i]) == "undefined") {
array.splice(i, 1);
i = i - 1;
}
}
return array;
}
1234567891011121314151617
filter方法
// 方法二:filter方法 [推荐写法]
var arr = ['A', '', 'B', null, undefined, 'C', ' '];
var r = arr.filter((s) => {
return s && s.trim(); // 注:IE9(不包含IE9)以下的版本没有trim()方法
});
console.log(r); //打印结果: ["A", "B", "C"]
去重
...new Set(array)
保留小数位:不显示的时候,默认值为0了,本应该为1的【解决方案:】
<gmd-form-model-item v-if="formData.createType == 1" label="结果展示方式" prop="valueType">
<gmd-form-model-item style="display:inline-block;margin:0;width: 100px;">
<gmd-select v-model="formData.valueType">
<gmd-select-option :value="1">整数</gmd-select-option>
<gmd-select-option :value="2">小数</gmd-select-option>
<gmd-select-option :value="3">百分数</gmd-select-option>
</gmd-select>
</gmd-form-model-item>
<gmd-form-model-item
v-if="formData.valueType !== 1"
label="保留小数位"
prop="dataDigits"
:label-col="{span:8}"
style="display:inline-block;margin:0;width: calc(100% - 100px);"
>
<gmd-input-number
v-model="formData.dataDigits"
:disabled="formData.valueType === 1"
:min="1"
:max="9"
/>
<!-- @keydown.native="handleBackspace"-->
</gmd-form-model-item>
</gmd-form-model-item>
watch: {
async 'formData.dataDigits'(v) {
if (!v) {
await this.$nextTick()
this.formData.dataDigits = 1
}
},
},
多重判断简化【写个配置表】
if (this.formData.analysisMethod) {
// 设分析维度验证:【数据类型--分析方法】配置表
const config = {
2: [2, 3, 4, 5],
3: [2, 5],
4: [2, 5],
}
if (config[row.type]?.includes(this.formData.analysisMethod)) {
return this.$message.error('当前分析方法不支持此数据类型')
}
} else {
return this.$message.warning('请先补充分析方法')
}
<gmd-select
:disabled="formData.createType == 1"
v-model="formData.analysisMethod"
placeholder="请选择分析方法(单选)"
class="indexsSelect"
>
<gmd-select-option
v-for="fc in configs.fcList"
:key="fc.value"
:value="fc.value"
:disabled="analysisConfig[fc.value] && analysisConfig[fc.value].includes(formData.dataType)"
>{{ fc.name }}</gmd-select-option>
</gmd-select>
data() {
return {
analysisConfig: {
2: [2, 3, 4],
3: [2],
4: [2],
5: [2, 3, 4],
}
}
}
keycode键值码表
HTML
用户名:
密码:
JavaScript:
JumpByEnter(UserPwd) 函数功能:输入完用户名按回车,焦点转向密码输入框
IsEnterKeyPress()功能:输入完密码并按回车,则登录
function JumpByEnter(NextElement){\
var lKeyCode = (navigator.appname=="Netscape")?event.which:window.event.keyCode; //event.keyCode按的建的代码,13表示回车\
if ( lKeyCode == 13 ){
NextElement.focus();\
}
function IsEnterKeyPress(){\
var lKeyCode = (navigator.appname=="Netscape")?event.which:event.keyCode;\
if ( lKeyCode == 13 ){\
Login();\
}\
else\
return false;\
}
irfirefox2.0中不支持 window.event.keyCode,
但是我们可以用event.which代替。但是为了使其能更具有普遍的兼容性,最好用event.keyCode|| event.which.
| 字母和数字键的键码值(keyCode) | | | | | | | |
| ------------------- | -- | -- | -- | -- | -- | -- | -- |
| 按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 |
| A | 65 | J | 74 | S | 83 | 1 | 49 |
| B | 66 | K | 75 | T | 84 | 2 | 50 |
| C | 67 | L | 76 | U | 85 | 3 | 51 |
| D | 68 | M | 77 | V | 86 | 4 | 52 |
| E | 69 | N | 78 | W | 87 | 5 | 53 |
| F | 70 | O | 79 | X | 88 | 6 | 54 |
| G | 71 | P | 80 | Y | 89 | 7 | 55 |
| H | 72 | Q | 81 | Z | 90 | 8 | 56 |
| I | 73 | R | 82 | 0 | 48 | 9 | 57 |
| 数字键盘上的键的键码值(keyCode) | 功能键键码值(keyCode) | | | | | | |
| -------------------- | --------------- | ----- | --- | -- | --- | --- | --- |
| 按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 |
| 0 | 96 | 8 | 104 | F1 | 112 | F7 | 118 |
| 1 | 97 | 9 | 105 | F2 | 113 | F8 | 119 |
| 2 | 98 | * | 106 | F3 | 114 | F9 | 120 |
| 3 | 99 | + | 107 | F4 | 115 | F10 | 121 |
| 4 | 100 | Enter | 108 | F5 | 116 | F11 | 122 |
| 5 | 101 | - | 109 | F6 | 117 | F12 | 123 |
| 6 | 102 | . | 110 | | | | |
| 7 | 103 | / | 111 | | | | |
| 控制键键码值(keyCode) | | | | | | | |
| --------------- | -- | ---------- | -- | ----------- | --- | ---- | --- |
| 按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 |
| BackSpace | 8 | Esc | 27 | Right Arrow | 39 | -_ | 189 |
| Tab | 9 | Spacebar | 32 | Dw Arrow | 40 | .> | 190 |
| Clear | 12 | Page Up | 33 | Insert | 45 | /? | 191 |
| Enter | 13 | Page Down | 34 | Delete | 46 | `~ | 192 |
| Shift | 16 | End | 35 | Num Lock | 144 | [{ | 219 |
| Control | 17 | Home | 36 | ;: | 186 | | | 220 |
| Alt | 18 | Left Arrow | 37 | =+ | 187 | ]} | 221 |
| Cape Lock | 20 | Up Arrow | 38 | ,< | 188 | '" | 222 |
| 多媒体键码值(keyCode) | | | | | | | |
| --------------- | --- | -- | -- | -- | -- | -- | -- |
| 按键 | 键码 | 按键 | 键码 | 按键 | 键码 | 按键 | 键码 |
| 音量加 | 175 | | | | | | |
| 音量减 | 174 | | | | | | |
| 停止 | 179 | | | | | | |
| 静音 | 173 | | | | | | |
| 浏览器 | 172 | | | | | | |
| 邮件 | 180 | | | | | | |
| 搜索 | 170 | | | | | | |
| 收藏 | 171
输入框禁止删除操作--键盘backspace
handleBackspace() {
if (event.keyCode === 8) event.preventDefault()
},
关于div禁用点击事件
情景⼀:阻⽌外层div点击事件pointer-events: none;
<div class="out" style="pointer-events: none;">
<div class="in" onClick="inBlock()">这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/></div>
</div>
需要注意的是如果在外层div设置了禁⽌点击,则⾥层div的点击事件⽆效的
情景⼆:外层点击事件不受⾥⾯div影响
也就是说我只想点击透明部分隐藏我的遮罩层
<div class="out" onclick="outBlock()">
<div class="in">这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/></div>
</div>
这时候只需要在我的div中加⼀段代码,就能有效阻⽌内层点击事件对外层的影响
onClick="event.cancelBubble = true"或
onClick="event.stopPropagation();"
<div class="in" onClick="event.cancelBubble = true">这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/></div>
这两种⽅法都能够有效阻⽌事件的冒泡,区别⼤家可以看看其他博客。
情景三:若外层div与内层div都需要执⾏点击且不同事件
与情景⼆的情况相同,我们都需要阻⽌事件的进⼀步冒泡⾏为
<div class="out" onclick="outBlock()">
<div class="in" onClick="inBlock()">这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/>这是我的提⽰框<br/></div>
</div>
<script>
var div1 = document.getElementsByClassName("out");
var div2 = document.getElementsByClassName("in");
function outBlock(){
div1[0].style.display = "none"
}
function inBlock(){
alert("这是⼀个内层点击");
//event.cancelBubble = true;
event.stopPropagation();
}
</script>
异步--async和await
async created() {
this.getOpList()
await this.getDatasourceList() // 这里是await的方法,在这个方法里return能起到异步加载完再进行下一步操作
if (this.$route.name === '编辑指标') {
// 基础指标数据回显
const detail = await this.getElementDetail(this.$route.params.id)
this.formData = detail
this.formData.showDesc = true
if (detail.elementType === 1 && detail.createType !== 1) {
this.datasource = this.datasourceList.find(data => data.code === detail.sourceNumber)
this.eleDetail = detail
this.table = detail.fieldDetailVo
this.isAnalysis = (detail.fieldDetailVo.find(v => v.isAnalysis === 1)).fieldName
this.formData.dataType = (detail.fieldDetailVo.find(v => v.isAnalysis === 1)).type
let list = detail.fieldDetailVo.filter(v => v.queryList?.length)
list.forEach(item => {
this.filterV1BoList[item.fieldName] = item.queryList.map(v => {
v.equation = String(v.equation)
v.equationName = (this.opList.find(a => a.id === v.equation)).name
return v
})
item.linkType = item.queryList[0].linkType
this.getLogicText(item.fieldName)
})
this.formData.description = this.eleDetail.description
}
this.initOpenStatus = this.formData.openStatus
if (detail.elementType === 2) {
this.checkLowerLevel()
}
}
},
methods: {
async getDatasourceList() {
const res = await api.getDatasourceList()
this.datasourceList = res
return
},
}
宏任务
$nexTick()
[GMD UI] form表单 required 提示英文改中文
最近发现 el-form 的 el-form-item 配置 required 之后 提示是英文,类似 “xxx is required”:
...
即使是表单验证或是自定义校验规则,只要有在标签上设置的required,就会或是在 不经意间 出现英文提示。。。
正确做法:
去掉标签上设置的required;
使用 rules 上的 required 设置:
data() {
return {
rules: {
content: [
{ required: true, message: '请输入内容', trigger: 'blur' }
]
}
}
}
即使是自定义校验规则也必须使用 rules
上的 required
设置,才可以实现 * ,自定义校验规则 的 判空验证 不能代替 required
设置!!!
crypto.js加密+解密
/** * AES加密 【前端】
* @param content 明文
* @param encryptKey 秘钥,必须为16个字符组成
* @return 密文
* @throws Exception */
安装:npm i crypto.js
引入:import CryptoJS from 'crypto-js'
// 加密
let aseKey = '2022tianxrda0620' // 秘钥必须为:8/16/32位
let encrypt = CryptoJS.AES.encrypt(this.model.reportContent, CryptoJS.enc.Utf8.parse(aseKey), {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
}).toString()
this.model.reportContent = encrypt
// 解密
let decrypt = CryptoJS.AES.decrypt(data.reportContent, CryptoJS.enc.Utf8.parse(aseKey), {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
}).toString(CryptoJS.enc.Utf8)
data.reportContent = decrypt
场景:选择月报下拉框,多月多选,且每月只能选一项其余禁用;
<gmd-col :span="10">
<gmd-form-model-item
:label-col="{ span: 8 }"
:wrapper-col="{ span: 16 }"
label="选择月报名称"
prop="monthReportName"
>
<gmd-select
style="width:230px"
v-model="model.monthReportName"
placeholder="请选择测评月报"
@change="handleSetReport"
:mode="selectMode"
>
<gmd-select-option
v-for="item in monthReportOptions"
:key="item.id"
:value="item.id"
:disabled="handleDisabled(item)"
>
{{ item.monthName }}
</gmd-select-option>
</gmd-select>
</gmd-form-model-item>
</gmd-col>
handleDisabled(value) {
const date = new Date(value.fetchedAt)
const year = date.getFullYear()
const month = date.getMonth() + 1
let result = false
if (this.selectMode === 'multiple') {
this.model.monthReportName.forEach(val => {
this.monthReportOptions.find(item => {
if (item.id === val) {
let y = new Date(item.fetchedAt).getFullYear()
let m = new Date(item.fetchedAt).getMonth() + 1
if (y === year && m === month && item.id !== value.id) {
result = true
}
}
})
})
}
return result
},
导出功能
场景:页面的HTML内容导出word文档
async exportWord() {
let titleStr = `<div data-v-9ceee822="" style="text-align: center;margin-bottom: 20px"><h1 data-v-9ceee822="" style="font-size: 18px;line-height: 28px;margin-bottom: 5px;color: #0D1C28">${this.data.title}</h1><span data-v-9ceee822="">报告类型:${this.reportTypes[this.data.reportType] || '-'}</span></div>`
let params = {
connent: titleStr + this.data.reportContent,
fileName: this.data.title + '.doc',
}
const resData = await api.exportWord(params)
let arr = []
arr.push(resData.data)
const url = window.URL.createObjectURL(new Blob(arr))
const fileName = decodeURIComponent(resData.headers['content-disposition'].split(';')[1].split('=')[1])
newWindowTo(url, fileName)
},
newWindowTo方法:
// 创建一个<a></a>标签,点击后新窗口打开,然后移除该标签
export function newWindowTo(url, fileName) {
const alink = document.createElement('a')
alink.setAttribute('href', url)
alink.setAttribute('target', '_blank')
if (fileName) alink.setAttribute('download', fileName || true)
document.getElementsByTagName('body')[0].appendChild(alink)
alink.click()
alink.remove()
}
JS的decodeURIComponent()函数:decodeURIComponent() 函数可对 encodeURIComponent() 函数编码的 URI 进行解码。
场景:选择月报下拉框,多月多选且每月只能选一项其余禁用
【根据后台返回字段 fetchedAt: 2022-07-04】
<gmd-col :span="10">
<gmd-form-model-item
:label-col="{ span: 8 }"
:wrapper-col="{ span: 16 }"
label="选择月报名称"
prop="monthId"
>
<gmd-select
style="width: 230px"
v-model="model.monthId"
placeholder="请选择测评月报"
@change="handleSetReport"
:mode="selectMode"
:disabled="isEditting"
>
<gmd-select-option
v-for="item in monthReportOptions"
:key="item.id"
:value="item.id"
:disabled="handleDisabled(item)"
>
{{ item.monthName }}
</gmd-select-option>
</gmd-select>
</gmd-form-model-item>
</gmd-col>
handleDisabled(value) {
const date = new Date(value.fetchedAt)
const year = date.getFullYear()
const month = date.getMonth() + 1
let result = false
if (this.selectMode === 'multiple') {
this.model.monthId.forEach((val) => {
this.monthReportOptions.find((item) => {
if (item.id === val) {
let y = new Date(item.fetchedAt).getFullYear()
let m = new Date(item.fetchedAt).getMonth() + 1
if (y === year && m === month && item.id !== value.id) {
result = true
}
}
})
})
}
return result
},
生成随机几位小写字母
getEngNum() {
let result = []
for (let i = 0; i < 4; i++) {
let ranNum = Math.ceil(Math.random() * 25)
result.push(String.fromCharCode(65 + ranNum))
}
return result.join('').toLowerCase()
},
报错信息分析
vue报错Uncaught (in promise) TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
通常是因为:有个undefined的属性搞了散列【例如:let { data, count } = undefined】
ES6特性--属性的散列
ES6特性:属性的散列:前端必会数据结构与算法系列之散列表(四)
https://juejin.cn/post/6885534619039596557#heading-2
根据年月份获取天数
getDaysInMonth(year, month) {
// parseInt(number,type)这个函数后面如果不跟第2个参数来表示进制的话,默认是10进制。
let nowmonth = parseInt(month, 10)
let temp = new Date(year, nowmonth, 0)
return temp.getDate()
},
MutationObserver监听DOM
插入在可以找到dom的时候【监听dom操作】
例一:
hanldeObserver() {
if (this.isMonthReportContent) {
// 选择需要观察变动的节点(获取到DOM)
const oneMonthNode = document.getElementById('oneMonth')
const moreMonthNode = document.getElementById('moreMonth')
const targetNode = oneMonthNode ? oneMonthNode : moreMonthNode
// 观察器的配置(需要观察什么变动)
const config = { attributes: true, childList: true, subtree: true }
// 当观察到变动时执行的回调函数
const callback = () => {
console.log('触发回调11111')
this.model.finishType = 0
this.jgyTips = '修改问题情况后, 只能选择监管员处理'
}
// 创建一个观察器实例并传入回调函数
const observer = new MutationObserver(callback)
// 以上述配置开始观察目标节点
observer.observe(targetNode, config)
// 之后,可停止观察
// observer.disconnect()
}
},
例二:
// 使用MutationObserver方法监听DOM元素【某个DOM元素的高度变化】
function handleObserver() {
const queryBarRef = document.getElementById('query-bar')
const observer = new MutationObserver((mutationsList) => {
for (let mutation of mutationsList) {
if (mutation.type === 'attributes') {
console.log('Element height changed')
// 在DOM元素高度变化时执行的逻辑
if (queryBarRef.offsetHeight === 144) {
tableHeight.value = 468
} else {
tableHeight.value = 380
}
}
}
})
if (queryBarRef) {
observer.observe(queryBarRef, { attributes: true })
}
return () => {
if (queryBarRef) {
observer.disconnect()
}
}
}
可编辑DIV【可编辑框】
例一:
// 插入自定义内容至可编辑div框 Easy版[适用简单页面场景]
// function insertAtCursorInEditor(dom, text) {
// let sel, range
// if (window.getSelection) {
// sel = window.getSelection()
// if (!dom.contains(sel?.anchorNode)) {
// return false
// }
// if (sel.getRangeAt && sel.rangeCount) {
// range = sel.getRangeAt(0)
// range.deleteContents()
// let el = document.createElement('div')
// el.innerHTML = `<span contenteditable="false">${text}</span>`
// let frag = document.createDocumentFragment(),
// node,
// lastNode
// while ((node = el.firstChild)) {
// lastNode = frag.appendChild(node)
// }
// range.insertNode(frag)
// if (lastNode) {
// range = range.cloneRange()
// range.setStartAfter(lastNode)
// range.collapse(true)
// sel.removeAllRanges()
// sel.addRange(range)
// }
// }
// } else if (document.selection && document.selection.type !== 'Control') {
// document.selection.createRange().pasteHTML(text)
// }
// return true
// }
例二:
// Complex复杂版[适用某项目] [插入自定义内容至可编辑div框]
export function insertAtCursorInEditor(dom, text, isEditable = true) {
if (window.getSelection) {
if (!dom.savedRange) return false
const newNode = document.createElement('span')
newNode.contentEditable = isEditable
newNode.innerHTML = text
dom.savedRange.deleteContents()
dom.savedRange.insertNode(newNode)
dom.savedRange.setStartAfter(newNode)
dom.savedRange.setEndAfter(newNode)
const sel = window.getSelection()
sel.removeAllRanges()
sel.addRange(dom.savedRange)
} else if (document.selection && document.selection.type !== 'Control') {
document.selection.createRange().pasteHTML(text)
}
return true
}
// 例:《算法框组件封装》
// 可编辑div框内置方法【存储焦点位置】
const storeSelectionI = event => {
const objId = event.target.id
let [num1, num2] = getBothStrNum(objId)
const secDigitObjAreaRef = document.getElementById(objId)
const sel = window.getSelection()
if (sel.rangeCount > 0) {
secDigitObjAreaRef.savedRange = sel.getRangeAt(0)
}
firstTableData.value[sfEditModal.value.currentIndex].modelNumberArithmeticEditBo.secDigitList[num1].term.rulesTableData[
num2
].object = secDigitObjAreaRef.textContent
}
// 插入内容至可编辑div框
const secDigitObjAddText = (str, rowIndex, index, type) => {
const secDigitObjAreaRef = document.getElementById(`sec${rowIndex}obj${index}`)
secDigitObjAreaRef.focus()
let text = type === 0 ? `{${str}}` : str
const isEditable = type !== 0
insertAtCursorInEditor(secDigitObjAreaRef, text, isEditable)
firstTableData.value[sfEditModal.value.currentIndex].modelNumberArithmeticEditBo.secDigitList[rowIndex].term.rulesTableData[
index
].object = secDigitObjAreaRef.textContent
}
一些封装好的快捷小方法
// 获取单数字字符串-->数字
export function getAnStrNum(str) {
return str.match(/\d+/g).join('')
}
// 获取双数字字符串-->对应数字
export function getBothStrNum(str) {
let [, , num1, , num2] = str.match(/^(\D*)(\d+)(\D*)(\d+)$/)
return [num1, num2]
}
// 判断【两个带','的字符串】str2基于str1是否有新增项
export function whetherNewStr(str1, str2) {
let result = false
const set1 = new Set(str1.split(','))
const set2 = new Set(str2.split(','))
const newItems = [...set2].filter(item => !set1.has(item))
result = newItems.length > 0
return result
}
// 计算嵌套表格B相对于表格A的最终索引
const sumBLengthBeforeIndexA = (arrA, indexA, indexB) => {
let sum = 0
for (let i = 0; i < indexA; i++) {
sum += arrA[i].term.rulesTableData.length
}
return sum + indexB
}
// 判断是否为空数据(含多种数据类型)
function isNullOrUndefined(value) {
return value === null || value === undefined
}
function isEmptyString(value) {
return typeof value === 'string' && value.trim() === ''
}
function isEmptyObject(value) {
return Object.keys(value).length === 0 && value.constructor === Object
}
function isEmptyArray(value) {
return Array.isArray(value) && value.length === 0
}
export const isEmpty = value => {
return isNullOrUndefined(value) || isEmptyString(value) || isEmptyObject(value) || isEmptyArray(value)
}
// 转换空数据为'---'(数据类型为数组)
export const transferEmptyData = table => {
table.map(item => {
Object.entries(item).forEach(([k, v]) => {
if (v === '' || v === null) item[k] = '---'
})
})
return table
}
// 转换空数据为'---'(数据类型为对象)
export const transferEmptyObjData = data => {
Object.entries(data).forEach(([k, v]) => {
if (v === '' || v === null) data[k] = '---'
})
return data
}
// 清空对象
export const emptyObjData = data => {
Object.entries(data).forEach(([k, v]) => {
data[k] = ''
})
return data
}
// 正则校验是否为日期时间格式
export const isDateTime = str => {
const reg = /^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})$/
return reg.test(str)
}
导出/下载【使用window.open】
function handleDownload(id) {
const baseUrl = window.location.origin
const devUrl = import.meta.env.MODE === 'development' ? '/ythjgpt-eas' : '/ythjgpt-admin/admin/apis/ythjgpt-eas'
// const url = location.origin + devUrl + `/file/manage/download?fileRecordId=${id}`
const url = `${baseUrl}${devUrl}/file/manage/download?fileRecordId=${id}`
window.open(url)
}
Vue3--自定义Hooks
例:
export function usePagination(handleSearch) {
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
showQuickJumper: true,
pageSizeOptions: ['10', '20', '30', '40', '50'],
showSizeChanger: true,
showTotal: total => `共 ${total} 条数据`
})
function pageChange(pagination) {
setPagination(pagination)
handleSearch?.(false)
}
function setPagination(data) {
const { current, pageSize, total } = data
pagination.value.current = current
pagination.value.pageSize = pageSize
pagination.value.total = total
}
const showSizeChange = (current, pageSize) => {
pagination.value.pageSize = pageSize
}
return {
pagination,
pageChange,
showSizeChange
}
}