2021
3.28
TS 枚举
- ts 枚举写了注释后,在文件外面使用的地方也会有提示。(必须写在前面)
Jsonp 原理
- 主要就是利用了
script标签的src没有跨域限制来完成的。
<script type='text/javascript'>
window.jsonpCallback = function (res) {
console.log(res)
}
</script>
<script src='http://localhost:8080/jsonp?id=1&cb=jsonpCallback' type='text/javascript'></script>- 注意的点就是回调函数的名称需要前后端确认好,如这里的
cb。
const Koa = require('koa');
const app = new Koa();
const items = [
{ id: 1, title: 'title1' },
{ id: 2, title: 'title2' }
];
app.use(async (ctx, next) => {
if (ctx.path === '/api/jsonp') {
const { cb, id } = ctx.query;
const title = items.find((item) => item.id == id)['title'];
ctx.body = `${cb}(${JSON.stringify({ title })})`;
return;
}
});
app.listen(8080, () => {
console.log('listen 8080...');
});4.2
JavaScript 里面的数组下标一定是数字吗?
- 不一定,数组也是一个对象,可以通过
[].key的形式来赋值。
4.7
react 中的 setState() 函数的第二个参数
- setState的第二个回调函数会在更新state,重新触发render后执行。
React 中的高阶组件(HOC)与 Render Props 的概念与对比。
Render Props 更灵活。
4.9
大图片的线性加载和渐进式加载
- 线性加载其实就是在我们浏览网页时常看见的那种 —— 网速足够慢或者图片尺寸过大时,可以看到图片的加载方式由上至下,一点一点的加载出来。
- 渐进式 则如同名字一般, 它会先显示低分辨率的近似图像,再逐步的增加图片分辨率(模糊到清晰)。
4.12
webpack 热更新原理
如上图所示,右侧 Server 端是
webpack-dev-server启动本地服务,内部实现其实是用express起的服务。1、服务端和客户端使用的是
websocket实现长连接。2、
webpack在本地开发用webpack-dev-server起服务同时开启了热更新之后,webpack会监听源文件的更改。 - 当你保存文件时,webpack会重新打包编译一次代码同时生成一个hash值、改动模块的json文件、改动模块的js文件。 - 编译完成后通过websocket把当前编译后文件的hash值发给客户端。3、客户端收到推送过来的
hash值,会和上次的hash值比较 - 一样的话会读取缓存 - 不一样则通过ajax和jsonp从服务器端获取最新的文件4、最后通过
内存文件系统去替换有修改的内容,实现局部刷新。
参考——https://juejin.cn/post/6844903933157048333#heading-32
4.13
React JSX 怎么变成真实 DOM 的
- 首先我们在 react 中写的
jsx/tsx会通过babel被编译为 React.createElement()

React.createElement()到底做了什么?这个函数的入参如下:
javascriptexport function createElement(type, config, children)React.createElement()有三个参数,这三个参数包括了创建一个元素所要知道的所有信息。type:用来标识节点类型,可以是一些原生的HTML标签,也可以是React中的组件。config:这个参数是以对象形式传入的,里面存放的是节点所有的属性。(key、className 等等)。children以对象形式传入,它记录的是组件标签之间嵌套的内容。(以 createElement() 的形式)。
比如下 DOM 结构:
html<ul className="list"> <li key="1">1</li> <li key="2">2</li> </ul>对应的是如下形式的
createElement()调用:jsReact.createElement( 'ul', { // 传入属性键值对 className: 'list' // 从第三个入参开始往后,传入的参数都是 children }, React.createElement( 'li', { key: '1' }, '1' ), React.createElement( 'li', { key: '2' }, '2' ) );createElement函数在对传进来的参数进行一顿处理之后,最后return了一个ReactElement函数,并传入处理过后的参数。
其实在
React.createElement中没有十分复杂的涉及算法或真实 DOM 的逻辑,它的每一个步骤几乎都是在格式化数据。说得更直白点,createElement 就像是开发者和 ReactElement 调用之间的一个“转换器”、一个数据处理层。它可以从开发者处接受相对简单的参数,然后将这些参数按照 ReactElement 的预期做一层格式化,最终通过调用 ReactElement 来实现元素的创建。
typescript 中的枚举 enum 类型其实是数字 number 的子类型
- number 类型可以理解为所有的数字,而枚举类型 enum 可以理解为有限个的数字。
4.14
关于 React 中的合成事件的事件池
- 在 React 17 之前,
合成事件对象会被放进一个叫事件池的地方统一管理。 - 这样做的目的是能够实现
事件对象的复用,进而提高性能。 - 但是这样处理的话,每当事件处理函数执行完毕之后,对应的合成事件对象就会被
"格式化",为下一次复用做准备,这就意味着我们在事件处理函数执行完毕之后就拿不到事件对象了。如下这个例子(官方提供)
function handleChange(e) {
// This won't work because the event object gets reused.
setTimeout(() => {
console.log(e.target.value); // Too late!
}, 100);
}- 如果你在一个 DOM 元素上绑定上面这个事件处理函数,触发之后控制台会提示如下信息:
Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property `target` on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use `event.persist()`. See https://fb.me/react-event-pooling for more information.- 根据这个提示信息能够看到解决方法:要想拿到目标事件对象,必须显式地告诉 React——我永远需要它,也就是调用
e.persist()函数,像下面这样:
function handleChange(e) {
// This won't work because the event object gets reused.
event.persist();
setTimeout(() => {
console.log(e.target.value); // Too late!
}, 100);
}- React 17 拥抱了新时代的潮流,重新在研发体验和向下兼容性能之间做了选择,这一次,它选择了前者——放弃事件池,为每一个合成事件创建新的对象。因此在 React 17 中,我们不需要 e.persist(),也可以随时随地访问我们想要的事件对象。
4.15
ES6 字符串新增方法
includes()、startsWith()、 endsWith()
传统上,JavaScript 只有indexOf方法,可以用来****。ES6 又提供了三种新方法。
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
let s = 'Hello world!';
s.startsWith('Hello'); // true
s.endsWith('!'); // true
s.includes('o'); // true- 这三个方法都支持第二个参数,表示开始搜索的位置。
let s = 'Hello world!';
s.startsWith('world', 6); // true
s.endsWith('Hello', 5); // true
s.includes('Hello', 6); // false- 上面代码表示,使用第二个参数
n时,endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。
repeat()
repeat方法返回一个新字符串,表示将原字符串重复n次。- 参数如果是小数,会被取整。
- 如果参数是负数或者
Infinity则会报错。 - 但是,如果参数是 0 到-1 之间的小数,则等同于 0,这是因为会先进行取整运算。0 到-1 之间的小数,取整以后等于
-0,repeat视同为 0。参数NaN等同于 0。如果repeat的参数是字符串,则会先转换成数字。
'jing'.repeat(3); // "jingjingjing"
'hao'.repeat(2); // "haohao"
'bao'.repeat(0); // ""
'hao'.repeat(2.9); // "haohao"
'haha'.repeat(Infinity);
// RangeError
'haha'.repeat(-1);
// RangeErrorpadStart()、padEnd()
- ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。
padStart()用于头部补全,padEnd()用于尾部补全。
'x'.padStart(5, 'ab'); // 'ababx'
'x'.padStart(4, 'ab'); // 'abax'
'x'.padEnd(5, 'ab'); // 'xabab'
'x'.padEnd(4, 'ab'); // 'xaba'- 上面代码中,
padStart()和padEnd()一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。 - 如果原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串。
- 如果用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截去超出位数的补全字符串。
- 如果省略第二个参数,默认使用空格补全长度。
padStart()的常见用途是为数值补全指定位数。下面代码生成 10 位的数值字符串。
'1'.padStart(10, '0'); // "0000000001"
'12'.padStart(10, '0'); // "0000000012"
'123456'.padStart(10, '0'); // "0000123456"trimStart()、trimEnd()
ES2019 对字符串实例新增了trimStart()和trimEnd()这两个方法。它们的行为与trim()一致,trimStart()消除字符串头部的空格,trimEnd()消除尾部的空格。它们返回的都是新字符串,不会修改原始字符串。
const s = ' abc ';
s.trim(); // "abc"
s.trimStart(); // "abc "
s.trimEnd(); // " abc"- 上面代码中,
trimStart()只消除头部的空格,保留尾部的空格。trimEnd()也是类似行为。 - 除了空格键,这两个方法对字符串头部(或尾部)的 tab 键、换行符等不可见的空白符号也有效。
- 浏览器还部署了额外的两个方法,
trimLeft()是trimStart()的别名,trimRight()是trimEnd()的别名。
matchAll()
matchAll()方法返回一个正则表达式在当前字符串的所有匹配。
replaceAll
历史上,字符串的实例方法replace()只能替换第一个匹配。
'aabbcc'.replace('b', '_');
// 'aa_bcc'- 如果要替换所有的匹配,不得不使用正则表达式的
g修饰符。 - 正则表达式毕竟不是那么方便和直观,ES2021 引入了
replaceAll()方法,可以一次性替换所有匹配。
'aabbcc'.replaceAll('b', '_');
// 'aa__cc'详见阮一峰 ES6
4.27
对象中的 key
- 任何对象作为对象的
key的时候,都会被转成'[object Object]'。 - 如果是函数作为对象的
key的时候,会把整个函数字符串化作为key。
看下面代码:
var a = {};
var b = { jing: 'hao' };
var c = { test: 'jing' };
function jing() {
var jing = 999;
}
a[b] = 'b';
a[c] = 'c';
a[jing] = 'jing';
console.log(a);
// 输出结果如下:
{
'[object Object]': 'c',
'function jing() {\n\tvar jing = 999;\n}': 'jing'
}Symbol 类型作为 key
再看下面这段代码
var a = {};
var b = Symbol('123');
var c = Symbol('123');
a[b] = 'b';
a[c] = 'c';
console.log(a);
console.log(a[b]);
console.log(a[c]);
console.log(Object.keys(a));
// 对应输出结果分别如下:
// { [Symbol(123)]: 'b', [Symbol(123)]: 'c' }
// b
// c
// []Symbol 定义的属性不会出现在下面循环中:
- for in:可获取原型属性,不可获取不可枚举属性
- for of:不可遍历对象,可遍历数组
- Object.keys:原型属性和不可枚举属性都不能获取
- Object.getOwnPropertyByNames:不可获取原型属性,可获取不可枚举属性
- JSON.stringify:原型属性和不可枚举属性都不能获取
- Reflect.ownKeys:可获取不可枚举和 Symbol,不可获取原型
所以上面 Object.keys(a) 的结果是 []
2021-7-3
Vue 项目中支持 less 定义全局的 css 变量
- 基于 sass-resources-loader 包实现
npm install sass-resources-loader --save-dev- 然后在构建文件中添加 loader
{
test: /\.less$/,
use: [
{
loader: 'vue-style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'less-loader'
},
{
loader: 'sass-resources-loader',
options: {
resources: [path.resolve(__dirname, '../src/styles/variable.less')]
//这里文件路径就是定义全局公共变量的文件
}
}
]
},2021-7-5
span:nth-of-type(1)
- 选中当前父类下的第几个子元素标签(括号内数字 1 就是第一个)
2021-7-26
vue key 的问题
- 今天碰到一个 Vue 中 key 的问题。
- 自定义列拖拽顺序后页面表格不会更新列顺序的问题。
- 后来涛哥发现是 key 的问题,因为表格的 key 我用的是每列的 name ,在拖拽的时候虽然数据的顺序变化了,但是每一项的数据的 key 还是一样,所以 Vue 虚拟 DOM 自己优化了,不会更新页面。
2021-8-4
怎么解决 G2 图表数据更新了旧图表还在页面上造成多个重复的图表。
图表根据条件查询到的数据渲染,查询后旧图表没清除,造成页面显示多个图表。
jslet chartCurrent=null//图表初始值为null paintChart=()=>{ chartCurrent&&chartCurrent.destroy()//chartCurrent存在就销毁重新绘制chart let chart = new G2.Chart({ container: 'circle', autoFit: true, height: 600, padding:'auto' }); } chart.source(data); chart.interval().position('date*expected'); chart.render(); chartCurrent=chart https://blog.csdn.net/weixin_44471622/article/details/105221258
2021-9-20
1、Vue 中给组件上绑定原生事件
- Vue 中给组件上绑定原生事件的时候一定要加上
.native - 没加的话会在组件内部找事件,加上了就是在当前组件内找定义事件。
2、去掉滚动条方法
scrollbar-width: none; /* firefox */
-ms-overflow-style: none; /* IE 10+ */
&::-webkit-scrollbar {
display: none; /* Chrome Safari */
}2021-9-25
设置表格 td 最大宽度,里面内容换行
- 设置表格 td 最大宽度,里面内容换行。
- 一般字母的话会被浏览器默认是一个字符串或者说一个单词,所以不会自动换行。
table-layout:fixed;
td {
max-width: 200px;
word-wrap:break-word;
}2021-9-26
Vue 动态组件
- Vue 动态组件使用(有需要可以加 keep-alive)
<template>
<div class="tidb-colonyInfo">
<div class="top">
<h3>集群:test</h3>
<el-tag type="success" effect="dark">运行中</el-tag>
</div>
<div class="radio-button">
<el-radio-group v-model="defaultComponent" @change="changeCom">
<el-radio-button label="ColonyBaseInfo">基本信息</el-radio-button>
<el-radio-button label="Monitor">监控</el-radio-button>
<el-radio-button label="AlarmConf">报警配置</el-radio-button>
<el-radio-button label="ParameterConf">参数设置</el-radio-button>
<el-radio-button label="OperationRecord">操作记录</el-radio-button>
</el-radio-group>
</div>
<component :is="viewCom"></component>
</div>
</template>
<script>
import ColonyBaseInfo from '@/package/tidb-database/colonyManage/components/colonyBaseInfo.vue';
import Monitor from '@/package/tidb-database/colonyManage/components/monitor.vue';
import AlarmConf from '@/package/tidb-database/colonyManage/components/alarmConf.vue';
import ParameterConf from '@/package/tidb-database/colonyManage/components/parameterConf.vue';
import OperationRecord from '@/package/tidb-database/colonyManage/components/operationRecord.vue';
import { _getSystemList } from '@/services/tidb-database/databaseManage/index';
export default {
name: 'tidb-colonyInfo',
components: {
ColonyBaseInfo,
Monitor,
AlarmConf,
ParameterConf,
OperationRecord
},
data() {
return {
defaultComponent: 'ColonyBaseInfo',
viewCom: 'ColonyBaseInfo'
};
},
mounted() {},
methods: {
changeCom(val) {
this.viewCom = val;
}
}
};
</script>
<style scoped lang="less">
.tidb-colonyInfo {
.top {
h3 {
margin: 20px 20px 20px 0;
display: inline-block;
}
}
.radio-button {
margin-bottom: 20px;
}
}
</style>2021-9-28
element 折叠面板
- element 折叠面板展开图表从左边换到右边的方法
<template>
<el-collapse accordion v-model="activeNames" @change="handleChange">
<el-collapse-item name="1">
<span class="collapse-title" slot="title">一致性 Consistency</span>
<div>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;</div>
<div>在界面中一致:所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。</div>
</el-collapse-item>
<el-collapse-item name="2">
<span class="collapse-title" slot="title">反馈 Feedback</span>
<div>控制反馈:通过界面样式和交互动效让用户可以清晰的感知自己的操作;</div>
<div>页面反馈:操作后,通过页面元素的变化清晰地展现当前状态。</div>
</el-collapse-item>
<el-collapse-item name="3">
<span class="collapse-title" slot="title">效率 Efficiency</span>
<div>简化流程:设计简洁直观的操作流程;</div>
<div>清晰明确:语言表达清晰且表意明确,让用户快速理解进而作出决策;</div>
<div>帮助用户识别:界面简单直白,让用户快速识别而非回忆,减少用户记忆负担。</div>
</el-collapse-item>
<el-collapse-item name="4">
<span class="collapse-title" slot="title">可控 Controllability</span>
<div>用户决策:根据场景可给予用户操作建议或安全提示,但不能代替用户进行决策;</div>
<div>结果可控:用户可以自由的进行操作,包括撤销、回退和终止当前操作等。</div>
</el-collapse-item>
</el-collapse>
</template>
<style scoped lang="less">
.collapse-title {
flex: 1 0 90%;
order: 1;
}
.el-collapse-item__header {
flex: 1 0 auto;
order: -1;
}
</style>2021-10-8
1、iframe 嵌入、postmessage
<template>
<div class="tidb-monitor">
<div class="tabs">
<el-tabs v-model="iframeSrc">
<el-tab-pane label="集群监控" :name="overview"></el-tab-pane>
<el-tab-pane label="PD节点监控" :name="pd"></el-tab-pane>
<el-tab-pane label="TiDB节点监控" :name="tidb"></el-tab-pane>
<el-tab-pane label="TiKV节点监控" :name="tikv"></el-tab-pane>
<el-tab-pane label="TiFlash节点监控" :name="tiflash"></el-tab-pane>
<el-tab-pane label="TiDB dashboard" :name="dashboard"></el-tab-pane>
</el-tabs>
</div>
<iframe id="monitor" @load="postMsg" ref="monitor" :src="iframeSrc" frameborder="0"></iframe>
</div>
</template>
<script>
import { _getColonySystemMonitor } from '@/services/tidb-database/colonyManage/index';
export default {
name: 'tidb-monitor',
data() {
return {
id: null, //集群 id
overview: null, //全局监控链接
pd: null, //PD监控链接
tidb: null, //TiDB监控链接
tikv: null, //TiKV监控链接
tiflash: null, //TiFlash监控链接
dashboard: null, //Tidb Dashboard链接
token: null, //Tidb Dashboard访问token
iframeSrc: null //iframe 的 src 地址
};
},
created() {
this.id = this.$route.query.id;
},
mounted() {
this.init();
},
methods: {
init() {
this.getColonySystemMonitor();
},
// 获取所有监控 ifram src 地址
async getColonySystemMonitor() {
const params = {
id: this.id
};
const res = await _getColonySystemMonitor(params);
if (res.success) {
const result = res.result;
this.overview = result.overview;
this.pd = result.pd;
this.tidb = result.tidb;
this.tikv = result.tikv;
this.tiflash = result.tiflash;
this.dashboard = result.dashboard;
this.token = result.token;
this.iframeSrc = this.overview;
}
},
// 利用 postMessage 与 iframe 窗口通信进行登录操作
postMsg() {
this.$refs.monitor.contentWindow.postMessage(
{
type: 'DASHBOARD_PORTAL_EVENT',
token: this.token,
lang: 'zh',
hideNav: false,
redirectPath: '/overview'
},
'*'
);
}
}
};
</script>
<style scoped lang="less">
.tidb-monitor {
height: 100%;
width: 100%;
.tabs {
height: 50px;
}
#monitor {
width: 100%;
border: none;
margin: 0;
padding: 0;
z-index: 999999;
height: calc(~'100% - 50px');
}
}
</style>2021-10-9
1、自定义 hook—useLocalStorage
2、elementui 更改 el-table 表头背景颜色和字体颜色
<el-table :header-cell-style="{background:'#eef1f6',color:'#606266'}"> ... </el-table>3、element Tooltip 背景颜色样式修改
- 使用这个属性
popper-class添加一个 class.
<el-tooltip popper-class="atooltip" effect="light" content="常规业务推荐使用,不限系统" placement="top">
<i class="el-icon-warning"></i>
</el-tooltip>- 重置样式重写一个 style 文件,就在当前组价创建也可以,但是不能 添加 scope,否则无效
<style lang="less">
.atooltip.el-tooltip__popper {
border: none;
box-shadow: 2px 2px 5px #ccc, -2px -2px 5px #ccc;
}
.atooltip.el-tooltip__popper[x-placement^='top'] .popper__arrow {
border-top-color: #fff;
}
.atooltip.el-tooltip__popper[x-placement^='top'] .popper__arrow:after {
border-top-color: #fff;
}
.atooltip {
background: #fff !important;
}
</style>2021-10-11
1、8-20 位,至少包含字母、数字、特殊符号中的任意两种正则
/^(?:(?=.*[a-zA-Z])(?=.*[\d])|(?=.*[!#+,.\\=:=@-])(?=.*[\d])|(?=.*[!#+,.\\=:=@-])(?=.*[a-zA-Z])).{8,20}$/;2021-10-13
1、vue 中使用 css3 的 calc()函数问题
- 1.常用的长度值几乎都可以使用 calc()函数进行计算(包括%,px 等),calc()函数支持 “+”, “-”, “*”, “/” 运算,运算符前后必须空格隔开,否则不生效。
- 2.calc()函数在 less 中不能使用不生效(less 的运算方式和 calc 发送了冲突),比如 calc(100% - 250px )会被编译为 calc(-150% ),解决办法将函数写为 calc(~'100% - 250px')。
<style scoped lang="less">
.tidb-monitor {
height: 100%;
width: 100%;
.tabs {
height: 50px;
}
#monitor {
width: 100%;
border: none;
margin: 0;
padding: 0;
z-index: 999999;
height: calc(~'100% - 50px');
}
}
</style>2021-10-14
1、vue 中的 filters
- vue 中的 filters 也是不能用 this 的
- 所以在 filters 中想要用 data 中的数据,必须直接在 template 中传过来。
- 在 filters 中函数接受的第一个参数默认是过滤的目标值,从第二个参数才是传进来的参数
<el-table-column prop="status" label="状态">
<template slot-scope="scope">
{{ scope.row.status | handleStatus(statusObjArr) }}
</template>
</el-table-column>
<script>
export default {
filters: {
handleStatus(val, statusObjArr) {
let targetStatus = '';
statusObjArr.forEach((item) => {
if (item.value === val) {
targetStatus = item.label;
}
});
return targetStatus;
}
}
};
</script>2021-10-15
1、编辑器实战
import * as monaco from 'monaco-editor';
import { format } from 'sql-formatter';
class MonacoEditor {
constructor() {
// 正常情况系编辑器实例
this.monacoEditorInstance = null;
// diff下编辑器实例
this.diffMonacoEditorInstance = null;
this.defaultOptions = {
selectOnLineNumbers: true,
roundedSelection: true,
readOnly: false, // 只读
cursorStyle: 'line', //光标样式
automaticLayout: true, //自动布局
glyphMargin: true, //字形边缘
useTabStops: false,
fontSize: 14, //字体大小
autoIndent: true, //自动布局
quickSuggestionsDelay: 0, //代码提示延时
language: 'sql', //语言
theme: 'vs',
formatOnType: true,
minimap: {
enabled: false
},
scrollBeyondLastLine: false
};
// 当前编辑器是否处于diff的状态
this.currentEditorDiff = false;
// 变更堆栈信息
// this.viewState = null;
}
/**
* 初始化
* @param domId
* @param options
*/
init(domId = '', options = {}) {
if (!this.monacoEditorInstance) {
const el = document.getElementById(domId);
if (el) {
const allOptions = Object.assign(this.defaultOptions, options);
this.monacoEditorInstance = monaco.editor.create(el, allOptions);
this.registerFormat(allOptions.language);
this.addListenResize();
} else {
throw new Error('未找到dom');
}
}
}
// 编辑器内容变更
onDidChangeModelContent(callback = undefined) {
if (callback) {
const instance = this.getEditor(this.currentEditorDiff);
if (instance) {
instance.onDidChangeModelContent(() => {
callback && callback();
});
}
}
}
/**
* 销毁
*/
destroyed() {
if (this.monacoEditorInstance) {
this.monacoEditorInstance.dispose();
this.monacoEditorInstance = null;
}
if (this.diffMonacoEditorInstance) {
this.diffMonacoEditorInstance?.dispose();
this.diffMonacoEditorInstance = null;
}
}
// 添加监听
addListenResize() {
window.addEventListener('resize', () => {
if (this.monacoEditorInstance) {
this.monacoEditorInstance.layout();
}
});
}
/**
* 设置编辑器的值
* @param value
*/
setValues(value) {
const instance = this.getEditor(this.currentEditorDiff);
if (instance) {
if (!value) {
value = '';
}
instance.setValue(value);
}
}
// 获取编辑的值
getValues() {
const instance = this.getEditor(this.currentEditorDiff);
if (instance) {
return instance.getValue();
}
}
// 获取编辑器中选中的值
getSelectedValue() {
const instance = this.getEditor(this.currentEditorDiff);
if (instance) {
return instance.getModel().getValueInRange(instance.getSelection());
}
}
// 撤销
revoke() {
const instance = this.getEditor(this.currentEditorDiff);
if (instance) {
instance.trigger('anyString', 'undo');
}
}
// 重做
redo() {
const instance = this.getEditor(this.currentEditorDiff);
if (instance) {
instance.trigger('anyString', 'redo');
}
}
// 格式化
format() {
const instance = this.getEditor(this.currentEditorDiff);
if (instance) {
instance.trigger('anyString', 'editor.action.formatDocument');
}
}
// 注册格式化方法
registerFormat(type) {
switch (type) {
case 'sql': {
monaco.languages.registerDocumentFormattingEditProvider('sql', {
async provideDocumentFormattingEdits(model) {
let formatted = await format(model.getValue());
return [
{
range: model.getFullModelRange(),
text: formatted
}
];
}
});
}
}
}
/**
* 版本对比
* @param domId
* @param lhsData
* @param rhsData
*/
diff(domId, lhsData, rhsData, languages = 'sql', changeCallback = undefined) {
if (!this.diffMonacoEditorInstance) {
this.diffMonacoEditorInstance = monaco.editor.createDiffEditor(document.getElementById(domId), {
enableSplitViewResizing: false,
originalEditable: true,
scrollBeyondLastLine: false
});
}
let lhsModel = monaco.editor.createModel(lhsData, languages);
let rhsModel = monaco.editor.createModel(rhsData, languages);
this.diffMonacoEditorInstance.setModel({
original: lhsModel,
modified: rhsModel
});
// 设置右侧diff只读
this.diffMonacoEditorInstance.getModifiedEditor().updateOptions({ readOnly: true });
/**
* hack写法
* @type {Element}
*/
const closeDiffReviewEl = document.getElementsByClassName('close-diff-review')[0];
if (closeDiffReviewEl) {
closeDiffReviewEl.click();
}
}
/**
* 设置当前编辑器的状态
* @returns {boolean}
*/
setCurrentEditorStatus(status) {
this.currentEditorDiff = status;
}
/**
* 获取当前编辑器的状态
* @returns {boolean}
*/
getCurrentEditorStatus() {
return this.currentEditorDiff;
}
/**
* 获取当前实例
* @returns {null}
*/
getEditor(isDiff = false) {
if (isDiff) {
return this.diffMonacoEditorInstance?.getOriginalEditor();
} else {
return this.monacoEditorInstance;
}
}
/**
* 设置编辑器为只读
*/
setEditorReadOnly() {
const instance = this.getEditor(this.currentEditorDiff);
instance.updateOptions({ readOnly: true });
}
// /**
// * 保存变更的堆栈信息
// */
// saveViewState() {
// const instance = this.getEditor(this.currentEditorDiff);
// if (instance) {
// this.viewState = instance.getModel();
// debugger;
// }
// }
//
// /**
// * 恢复变更记录
// */
// restoreViewState() {
// const instance = this.getEditor(this.currentEditorDiff);
// if (instance) {
// instance.restoreViewState(this.viewState);
// }
// }
}
export default new MonacoEditor();2021-10-20
1、Element 控制日期选择框只能选择一段时间范围内
- 只能选择 14 天内的值
pickerOptions: {
onPick: ({ maxDate, minDate }) => {
this.min = minDate && minDate.getTime();
},
disabledDate: (time) => {
let m = 13 * 24 * 60 * 60 * 1000;
if (this.min) {
return time.getTime() > this.min + m || time.getTime() < this.min - m;
}else {
return false;
}
},
},- 想要清除
disabledDate,方法如下: - 1、给日期选择框绑定一个
@on-change="handleChange"
handleChange(val) {
if (!val) {
this.min = null;
}
},- 2、这样点击日期选择框清除按钮就会触发事件取消
disabledDate。
2、Element 控制日期选择框设定上上个星期六星期天
const start = new Date();
const end = new Date();
const day = new Date().getDay(); //当前是星期几
start.setTime(start.getTime() - 3600 * 1000 * 24 * (day + 1));
end.setTime(end.getTime() - 3600 * 1000 * 24 * day);3、日期格式化工具化函数
dateFormat(tempDate, fmt) {
var o = {
'M+': tempDate.getMonth() + 1, //月份
'd+': tempDate.getDate(), //日
'H+': tempDate.getHours(), //小时
'm+': tempDate.getMinutes(), //分
's+': tempDate.getSeconds(), //秒
'q+': Math.floor((tempDate.getMonth() + 3) / 3), //季度
S: tempDate.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (tempDate.getFullYear() + '').substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp('(' + k + ')').test(fmt))
fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length));
return fmt;
}
//使用方法
dateFormat(Date(), 'yyyy-MM-dd')2021-10-21
1、误把 .DS_Store 提交到了远程分支处理方法
1、终端中输入下面命令删除所有.DS_Store 文件。
shellfind . -name .DS_Store -print0 | xargs -0 git rm -f --ignore-unmatch2、然后提交并推送更改以从远程仓库中删除.DS_Store
git commit -m "Remove .DS_Store from everywhere"
git push origin master2021-10-29
1、Number.isInteger()—方法用来判断给定的参数是否为整数。(有点问题)
- 问题
Number.isInteger(8.0); //true- 原因
Number.isInteger =
Number.isInteger ||
function (value) {
return typeof value === 'number' && isFinite(value) && Math.floor(value) === value; //原因
};2021-11-03
1、element 在多选表格中加一行不需要 CheckBox 的问题
- 效果如下图

- 主要代码如下
<ui-table-pro
....其他属性
:cell-class-name="cellClassNameFn"
>
<ui-table-column
type="selection"
width="60"
:selectable="handledisabled"
></ui-table-column>
</ui-table-pro>
// 给特定的单元格设置类名
cellClassNameFn(row) {
if (row.rowIndex === 0) {
// 第一列且状态为 1 通过自定义样式隐藏复选框
return 'table-column-hidden';
}
},
//将这一列的 CheckBox disabled,防止全选时被选中
handledisabled(row, index) {
if (index === 0) {
return false;
} else {
return true;
}
},
//隐藏 CheckBox 的样式
/deep/ .table-column-hidden .checkbox {
display: none !important;
}2021-11-08
1、常见常用的伪元素
| 选择器 | 示例 | 示例描述 |
|---|---|---|
| ::after | p::after | 在每个 p 元素之后插入内容。 |
| ::before | p::before | 在每个 p 元素之前插入内容。 |
| ::first-letter | p::first-letter | 选择每个 p 元素的首字母。 |
| ::first-line | P::first-line | 选择每个 p 元素的首行。 |
| ::selection | p::selection | 选择用户选择的元素部分。 |
2021-11-09
1、css 实现模糊效果
- backdrop-filter
- filter
2、flex 布局子元素高度设置无效的原因及解决办法
原因
- 定义为 flex 布局元素的子元素,自动获得了 flex-shrink 的属性,这个属性是什么意思呢?
- 就是告诉子元素当父元素宽度不够用时,自己调整自己所占的宽度比
- 这个 flex-shrink 设置为 1 时,表示所有子元素大家同时缩小来适应总宽度。
- 当 flex-shrink 设置为 0 时,表示大家都不缩小适应。
- 原文链接:https://blog.csdn.net/ycg5250/article/details/117303044
解决办法
- 给子元素设置 flex-shrink:0
2021-11-11
1、css 选择器(:nth-child)
span: nth-child(-n + 3) //匹配前三个子元素中的span元素。;2021-11-18
1、element 级联选择器获取 label 的值
this.$refs.myCascader.getCheckedNodes()[0].pathLabels;2021-11-22
/*
* @Author: wangzhihao
* @Date: 2021-11-22 12:51:36
* @LastEditors: wangzhihao
* @LastEditTime: 2021-11-22 13:16:46
*/
//有意思的操作 可以改变 instanceof 操作符的结果
class Bar {}
class Baz extends Bar {
static [Symbol.hasInstance]() {
return false;
}
}
let b = new Baz();
console.log(Bar[Symbol.hasInstance](b)); // true
console.log(b instanceof Bar); // true
console.log(Baz[Symbol.hasInstance](b)); // false
console.log(b instanceof Baz); // false
//柯里化函数
const sum = function () {
const prev = [...arguments];
const fn = function () {
const cur = [...arguments];
return sum.apply(null, prev.concat(cur));
};
/**
* 优先走 valueOf
*/
// fn.valueOf = () => {
// return prev.reduce((p,c) => p - c);
// }
fn.toString = () => {
return prev.reduce((p, c) => p + c);
};
return fn;
};
// console.log(+sum(1,3)(1,4)(5)(2,0)); // 放开 valueOf 的结果就是 -14
console.log(+sum(1, 3)(1, 4)(5)(2, 0)); //162021-11-23
1、浏览器提供的复制操作
- navigator.clipboard.writeText(value)
- 更多操作详见阮一峰
async copyMiyaoAk() {
try {
await navigator.clipboard.writeText(this.AK);
this.$toast({
content: '复制成功!',
type: 'success',
});
} catch (err) {
this.$toast({
content: '复制失败!',
type: 'error',
});
}
},2021-11-25
1、webpack 端口
- 用在 webpack 配置里,参数可选。如下配置会优先以 8077 端口启动服务器,如果 8077 被占用了,会自动寻找下一个可用端口。
const portFinderSync = require('portfinder-sync')
devServer: {
port: portFinderSync.getPort(8077),
}2、css 中定义 class 时,中间有空格和没空格的区别是什么?
- example:两个 css 如下:
.example .pp {
color: orange;
}
.example.pp2 {
color: green;
}- 第一个样式生效的 html
<p class="example">
文字文字
<span class="pp">pp这个class生效</span>
</p>- 第二个样式生效的 html
<p class="example pp2">文字文字 pp2这个class生效</p>2021-12-06
1、正则表达式-仅支持小写字母、数字、下划线,且不能以下划线开头/结尾
/^(?!_)(?!.*_$)[a-zA-Z0-9_]+$/;2、正则断言相关
2021-12-14
1、video 标签相关
- 视频自动循环播放
在video标签上添加autoplay 和 loop 属性,需手动点击播放才可自动循环播放,想要一打开就让 video 自动循环播放需要添加muted属性,具体代码实现如下:
<video src="@/assets/homepage/homepage.mp4" :autoplay="true" :loop="true" muted="muted"></video>
russ