前端开发 大前端 W3Cbest

一个专注 WEB 开发的技术博客

0%

简要教程

notyf.js是一款超级简单的响应式纯js消息通知插件。它使用纯javascript来制作,没有任何外部依赖,通过简单的设置,即可生成漂亮的消息通知效果。

安装

可以通过npm来安装notyf.js消息通知插件。

npm i notyf

使用方法

在页面中引入notyf.min.css和notyf.min.js文件。

<html>
<head>
    ...
    <link rel="stylesheet" type="text/css" href="/path/to/notyf.min.css">
</head>
<body>
    ...
    <script src="/path/to/notyf.min.js" type="text/javascript"></script>
</body>
</html>

初始化插件

notyf.js消息通知插件的使用方法如下:

//创建一个Notyf实例对象
var notyf = new Notyf();
//显示一条警告消息
notyf.error('You must fill out the form before moving forward');
//显示一条成功消息
notyf.success('Your changes have been successfully saved!');

配置参数

notyf.js消息通知插件的可用配置参数如下:


|参数 |类型 |默认值 |描述 |

|delay |Number |2000 |消息通知显示的延迟时间,单位毫秒 |

|alertIcon |String |预定义图标|警告消息显示的图标的class类 |

|confirmIcon|String |预定义图标|成功消息显示的图标的class类 |

下面的例子是消息在用户点击按钮后1秒钟显示,并使用FontAwesome字体图标作为警告框和成功消息框的图标。

var notyf = new Notyf({
    delay: 1000,
    alertIcon: 'icon icon-exclamation-circle',
    confirmIcon: 'icon icon-check-circle'
})

演示地址:https://carlosroso.com/notyf/
github地址:https://github.com/caroso1222/notyf

1. 过滤唯一值

ES6 引入了 Set 对象和延展(spread)语法…,我们可以用它们来创建一个只包含唯一值的数组。

const array = [1, 1, 2, 3, 5, 5, 1]
const uniqueArray = […new Set(array)];
console.log(uniqueArray); // Result: [1, 2, 3, 5]

在 ES6 之前,获得同样的数组需要更多的代码! 这个技巧可以支持包含原始类型的数组:undefinednullbooleanstring 和 number

阅读全文 »

Cube.js 强大的开源框架,用于开发复杂的,定制的分析系统。由前端SDK和API后端组成,适用于大多数数据库,包括MySQL,Postreges和MongoDB。 Water.css 一个just-add-css框架,它可以应用样式而无需定义元素类。只需通过CDN将其包含在您的项目中,您的所有页面都会自动显示得更好。包括明暗主题,可通过SCSS定制。 Editor.js 富文本和媒体编辑器,以JSON格式输出数据。它是完全模块化的,由“块”组成,这意味着每个结构单元都是它自己的块(例如Paragraph,Heading,Image都是块),用户可以轻松编写自己的插件来进一步扩展编辑器。 Stepper 漂亮的数字Stepper组件,非常适合upvote / downvote控件或其他计数器元素。非常精美的动画,点击箭头时有一个黄油般的CSS效果。 DropCSS 彻底的CSS清理器,它可以获取HTML和CSS并仅返回实际使用的样式。它删除所有未使用的样式块,重复选择器,@ keyframes等。高度优化,速度极快。 Twemoji Twitter团队提供的优秀图书馆,可在所有平台上提供标准的Unicode表情符号支持。拥有超过3000个emojis和一个可靠的API,当您想要将emojis添加到您的应用程序时,它可以是完美的解决方案。 React LoadCon React组件,允许您使用一系列动态生成的图像为网站的图标设置动画。此效果可以用作进度或加载指示器,或者只是作为一个很酷的小动画来使您的页面脱颖而出。 Indigo Player 基于React的视频播放器,具有开箱即用的功能,如字幕,缩略图,质量选择等。高度可扩展,现代化,并支持大多数流行的视频格式和编解码器。 html2canvas 这个很酷的脚本获取页面中的元素和样式,并通过呈现DOM的副本来捕获“屏幕截图”。由于屏幕截图基于DOM,因此它们可能不是100%准确,但该库仍然是调试和自动化测试的绝佳工具。 Choices 轻量级库,用于制作高度可自定义的选择框,文本区域和其他表单输入。类似于Select2Selectize但没有jQuery依赖。

CSS布局中有一些概念,一旦你理解了它们,就能真正提高你的 CSS 布局能力。本文是关于块格式化上下文(BFC)的。你可能从未听说过这个术语,但是如果你曾经用CSS做过布局,你可能知道它是什么,理解什么是 BFC,怎么工作以及如何创建 BFC 非常有用,这些可以帮助你理解CSS中的布局是如何工作的。 在本文中,通过熟悉的示例来解释什么是 BFC。然后说明 display 的一个新值,只有当你理解了什么是 BFC 以及为什么需要它时,它才有意义。

什么是 BFC

在一个Web页面的CSS渲染中,块级格式化上下文 (Block Fromatting Context)是按照块级盒子布局的。W3C对BFC的定义如下: 浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容创建新的BFC(块级格式上下文)。 BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个 BFC 中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。 块格式化上下文(BFC)的行为通过一个简单的float示例很容易理解。在下面的示例中,我有一个框,其中包含向左浮动的图像和一些文本。如果我们有足够多的文本,它会环绕浮动的图像和边框,然后环绕整个区域。

I am a floated element.
I am text inside the outer box.

.outer {
border: 5 px dotted rgb(214, 129, 137);
border - radius: 5 px;
width: 450 px;
padding: 10 px;
margin - bottom: 40 px;
}
.float {
padding: 10 px;
border: 5 px solid rgba(214, 129, 137, .4);
border - radius: 5 px;
background - color: rgba(233, 78, 119, .4);
color: #fff;
float: left;
width: 200 px;
margin: 0 20 px 0 0;
}

如果我删除了一些文本,那么就没有足够的内容来包围图像,而且由于浮动被从文档流中脱离,所以边框会上升,并在图像下方,直到文本的高度。 这是因为当我们浮动一个元素时,文本所在的框的宽度保持不变,为给浮动元素腾出空间而缩短的是文本的行框。这就是为什么背景和边框会出现在浮动后面的原因。 我们通常有两种方法来解决这个布局问题。一种方法是使用 clearfix hack,它的作用是在文本和图像下面插入一个元素,并将其设置为 clear:both。另一种方法是使用 overflow 属性,其值不是缺省值 visible。

.outer {
overflow: auto;
}

overflow 以这种方式工作的原因是,使用 visible 的初值以外的任何值都会创建一个块格式化上下文,而 BFC 的一个特性是它包含浮动。

BFC 是布局中的一个迷你布局

你可以将 BFC 看作是页面内的一个迷你布局。一旦一个元素创建了一个 BFC,它就包含了所有的内容。正如我们所看到的,这包括浮动的元素,它们不再从盒子底部伸出来。BFC 还会导致一些其他有用的行为。 BFC 可以防止 margin 折叠 了解边距合并是另一个被低估的 CSS 技能。在下一个示例中,假设有一个背景颜色为灰色的 div。 这个 div 包含两个标签 p。外部 div 元素的 margin-bottom 为 40 像素,标签 p 的顶部和底部 margin 都是 20 像素。

// html

I am paragraph one and I have a margin top and bottom of 20px;

I am paragraph one and I have a margin top and bottom of 20px;

// css
.outer {
background-color: #ccc;
margin: 0 0 40px 0;
}
p {
padding: 0;
margin: 20px 0 20px 0;
background-color: rgb(233, 78, 119);
color: #fff;
}

因为 p 元素的 margin 和外部 div 上的 margin 之间没有任何东西,所以两个会折叠,因此 p 最终与 div 的顶部和底部齐平。 我们在 p 的上方和下方看不到任何灰色。 在CSS当中,相邻的两个盒子(可能是兄弟关系也可能是祖先关系)的外边距可以结合成一个单独的外边距。这种合并外边距的方式被称为折叠,并且因而所结合成的外边距称为折叠外边距。折叠的结果按照如下规则计算: 两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。 两个相邻的外边距都是负数时,折叠结果是两者绝对值的较大值。 两个外边距一正一负时,折叠结果是两者的相加的和。 产生折叠的必备条件:margin必须是邻接的! 如果我们把盒子设为 BFC,它现在包含了标签 p 和它们的边距,这样它们就不会折叠,我们可以看到边距后面容器的灰色背景。

.outer {
background-color: #ccc;
margin: 0 0 40px 0;
overflow: auto;
}

再一次,BFC 的工作是把东西装在盒子里,防止它们从盒子里跑出来。 BFC 可以阻止元素被浮动元素覆盖 你将熟悉 BFC 的这种行为,因为使用浮动的任何列类型布局都是这样工作的。如果一个项目创建了一个 BFC,那么该项目将不会包裹任何浮动元素。在下面的例子中,有如下 html 结构:

I am a floated element.
I am text

带有 float 类的项被向左浮动,因此 div 中的文本在它环绕 float 之后。 我可以通过将包裹文本的 div 设置为 BFC 来防止这种包裹行为。

.text {
overflow: auto;
}

这实际上是我们创建具有多个列的浮动布局的方法。浮动项还为该项创建了一个 BFC,因此,如果右边的列比左边的列高,那么我们的列就不会相互环绕。

See the Pen A BFC preventing wrapping of floats. by rachelandrew (@rachelandrew) on CodePen.

还有什么能创建 BFC?

除了使用 overflow 创建 BFC 外,其他一些 CSS 属性还创建 BFC。正如我们所看到的,浮动元素创建了 BFC。你的浮动项将包含它里面的任何东西。 使用以下方式都能创建 BFC

  • float 的值不是 none。
  • position 的值不是 static 或者 relative。
  • display 的值是 inline-block、table-cell、flex、table-caption 或者inline-flex
  • overflow 的值不是 visible

创建 BFC 的新方式

使用overflow或其他的方法创建BFC时会有两个问题。首先,这些方法本身是有自身的设计目的,所以在使用它们创建BFC时可能会产生副作用。例如,使用overflow创建BFC后在某些情况下可能会看到出现一个滚动条或者元素内容被裁切。 这是由于overflow属性的设计是用来让你告诉浏览器如何定义元素的溢出状态的。浏览器执行了它最基本的定义。 即使在没有任何不想要的副作用的情况下,使用 overflow 也可能会让其他开发人员感到困惑。为什么 overflow 设置为 auto 或 scroll?最初的开发者的意图是什么?他们想要这个组件上的滚动条吗? 最安全的做法应该是创建一个 BFC 时并不会带来任何副作用,它内部的元素都安全的呆在这个迷你布局中,这种方法不会引起任何意想不到的问题,也可以理解开发者的意图。CSS 工作组也十分认同这种想法,所以他们定制了一个新的属性值:display:flow-root。

See the Pen Using display: flow-root for common tasks by rachelandrew (@rachelandrew) on CodePen.

flow-root 浏览器支持情况 你可以使用display:flow-root安全的创建BFC,来解决上文中提到的各种问题:包裹浮动元素、阻止外边距叠加和阻止围绕浮动元素。

Can I Use flow-root? Data on support for the flow-root feature across the major browsers from caniuse.com.

浏览器对该属性的支持目前还是有限的,如果你觉得这个属性值很方便,请投票去让Edge也支持它。不过无论如何,你现在应该已经理解了什么是 BFC,以及如何使用 overflow 或其他方法来包裹浮动,以及知道了 BFC 可以阻止元素去环绕浮动元素,如果你想使用弹性或网格布局可以在一些不支持他们的浏览器中使用 BFC 的这些特性做降级处理。 理解浏览器如何布置网页是非常基础的。 虽然有时看起来无关紧要,但是这些小知识可以加快创建和调试 CSS 布局所需的时间。

javascript 是一门复杂的语言。如果你是一名 javascript 开发者,理解它的一些基础概念是很重要的。本文选取了 12 个 JS 开发者应该掌握的概念,但不代表 JS 开发者需要了解的全部内容。 注意:我会在 github 仓库JS Tips & Tidbits上持续更新这个列表,如果有兴趣欢迎 star。

1. 值 VS 引用

理解 javascript 中如何分配变量的值是写好代码的基础。如果你还不了解这些,你可能很容易写出无意中修改值的代码。 javascript 总是按值分配变量。但是请特别注意:当分配的值是 javascript 的 5 种原始类型(boolean null undefined string number)时,是分配的真正的值。而如果分配的值是 Array Function Object时,只会分配该对象在内存中的一个引用。 举个例子。在下面的代码中,var2 被赋值为 var1。因为 var1 是原始类型(string),var2 的值就是 var1 的 值,并且与 var1 是完全独立的两个值,只是它们都是同样的字符串。或者说,重新给 var2 赋值对 var1 没有影响。

let var1 = ‘My string’;
let var2 = var1;
var2 = ‘My new string’;
console.log(var1);
// ‘My string’
console.log(var2);
// ‘My new string’

和赋值对象进行比较:

let var1 = { name: ‘Jim’ };
let var2 = var1;
var2.name = ‘John’;
console.log(var1);
// { name: ‘John’ }
console.log(var2);
// { name: ‘John’ }

如果你期望像分配原始类型那样的结果,这里就会出现问题,修改 var2 同样会影响到 var1。如果你创建了一个无意中修改对象的函数,就可能有难以预料的错误。

2. 闭包

闭包是 javascript 中很重要的特性,可以实现变量的私有访问。在下面的例子中,createGreeter 返回了一个匿名函数,函数可以访问外层函数的 greeting 参数。

function createGreeter(greeting) {
return function(name) {
console.log(greeting + ‘, ‘ + name);
};
}
const sayHello = createGreeter(‘Hello’);
sayHello(‘Joe’);
// Hello, Joe

在实际编码中,你可能希望有一个初始化函数 apiConnect(apiKey) 能够返回某些方法会用到的 apiKey。这种情况下,apiKey 只需要提供一次即可。

function apiConnect(apiKey) {
function get(route) {
return fetch(`${route}?key=${apiKey}`);
}
function post(route, params) {
return fetch(route, {
method: ‘POST’,
body: JSON.stringify(params),
headers: {
Authorization: `Bearer ${apiKey}`,
},
});
}
return { get, post };
}
const api = apiConnect(‘my-secret-key’);
// No need to include the apiKey anymore
api.get(‘http://www.example.com/get-endpoint');
api.post(‘http://www.example.com/post-endpoint', { name: ‘Joe’ });

3. 解构

不要忽略 javascript 的参数解构!这是从对象中干净地提取属性的常用方法。

const obj = {
name: ‘Joe’,
food: ‘cake’,
};
const { name, food } = obj;
console.log(name, food);
// ‘Joe’ ‘cake’

如果你想将属性解构成不同的名称,参考下面的语法:

const obj = {
name: ‘Joe’,
food: ‘cake’,
};
const { name: myName, food: myFood } = obj;
console.log(myName, myFood);
// ‘Joe’ ‘cake’

下面的例子中,解构用来干净地将 person 对象传递给 introduce 函数。或者说,解构可以(经常)用来提取传递给函数的参数的属性。如果你熟悉 React,你可能见过下面的代码。

const person = {
name: ‘Eddie’,
age: 24,
};
function introduce({ name, age }) {
console.log(`I’m ${name} and I’m ${age} years old!`);
}
console.log(introduce(person));
// “I’m Eddie and I’m 24 years old!”

4. 展开运算符

一个相对简单的 javascript 概念。下面的例子中,Math.max 不能接收一个数组,而是接收单个值作为参数。展开运算符…就是用来把数组里的元素一个一个拉出来。

const arr = [4, 6, -1, 3, 10, 4];
const max = Math.max(…arr);
console.log(max);
// 10

5. 剩余运算符

说一下 javascript 的剩余运算符。你可以用它将任意数量的参数放入一个数组再传递给函数。

function myFunc(…args) {
console.log(args[0] + args[1]);
}
myFunc(1, 2, 3, 4);
// 3

6. 数组方法

javascript 的数组方法经常能让你很优雅、便捷地转换你想要的数据。我经常看到有关如何以某种方式操纵对象数组的问题。这正是数组方法的可用之处。 我将在这里介绍一些不同的数组方法,以类似的可能会混淆的方法来分类。这个列表并不全面,我鼓励你们在 MDN 上反复复习并练习这些方法。

map, filter, reduce

有人可能对这 3 个方法有些混乱。但这些都是转换数组或返回聚合值的有用方法。 map:返回一个新的数组,其中每个元素按指定函数进行转换。

const arr = [1, 2, 3, 4, 5, 6];
const mapped = arr.map(el => el + 20);
console.log(mapped);
// [21, 22, 23, 24, 25, 26]

filter:返回一个新的数组,其中只包括回调函数返回 true 的元素。

const arr = [1, 2, 3, 4, 5, 6];
const filtered = arr.filter(el => el === 2 el === 4);
console.log(filtered);
// [2, 4]

reduce:累加函数中指定的值。

const arr = [1, 2, 3, 4, 5, 6];
const reduced = arr.reduce((total, current) => total + current);
console.log(reduced);
// 21

find, findIndex, indexOf

这三个方法通常会被混为一谈,下面是使用方法: find:返回与指定条件匹配的第一个元素。不会再寻找其他匹配的元素。

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const found = arr.find(el => el > 5);
console.log(found);
// 6

注意,虽然 5 之后的元素都满足条件,但只会返回第一个匹配元素。 findIndex:和 find 的机制基本一样,只是会返回第一个匹配元素的索引值而不是返回该元素。来看下面的例子:

const arr = [‘Nick’, ‘Frank’, ‘Joe’, ‘Frank’];
const foundIndex = arr.findIndex(el => el === ‘Frank’);
console.log(foundIndex);
// 1

indexOf:和 findIndex 的机制基本一样,但它接收一个值而不是一个函数作为参数。你可以在只需要简单的逻辑,不需要使用函数来判断匹配元素时使用它。

const arr = [‘Nick’, ‘Frank’, ‘Joe’, ‘Frank’];
const foundIndex = arr.indexOf(‘Frank’);
console.log(foundIndex);
// 1

push, pop, shift, unshift

这是一组很棒的数组方法,可以让你有针对性地添加或删除数组中的元素。 push:在数组尾部添加一个元素。会修改原数组,返回添加到数组的元素。

let arr = [1, 2, 3, 4];
const pushed = arr.push(5);
console.log(arr);
// [1, 2, 3, 4, 5]
console.log(pushed);
// 5

pop:删除数组的最后一个元素。会修改原数组,返回被删除的元素。

let arr = [1, 2, 3, 4];
const popped = arr.pop();
console.log(arr);
// [1, 2, 3]
console.log(popped);
// 4

shift:删除数组的第一个元素。会修改原数组,返回被删除的元素。

let arr = [1, 2, 3, 4];
const shifted = arr.shift();
console.log(arr);
// [2, 3, 4]
console.log(shifted);
// 1

unshift:在数组头部添加一个元素。会修改原数组,不同于其他几个方法,这个方法返回数组的新的长度。

let arr = [1, 2, 3, 4];
const unshifted = arr.unshift(5, 6, 7);
console.log(arr);
// [5, 6, 7, 1, 2, 3, 4]
console.log(unshifted);
// 7

splice, slice

这 2 个方法会修改数组或返回一个子数组。 splice:通过删除或替换已存在的元素或插入新的元素来修改原数组的内容。会修改原数组。 下面的例子可以理解为:在索引为 1 的位置移除 0 个元素并插入了元素 b。

let arr = [‘a’, ‘c’, ‘d’, ‘e’];
arr.splice(1, 0, ‘b’);

slice:从指定的开始和结束位置返回数组的浅复制副本。如果没有指定结束位置,返回数组的剩余部分。重要的是,此方法不修改原数组而是返回所需要的子数组。

let arr = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’];
const sliced = arr.slice(2, 4);
console.log(sliced);
// [‘c’, ‘d’]
console.log(arr);
// [‘a’, ‘b’, ‘c’, ‘d’, ‘e’]

sort

sort:基于提供的函数对数组进行排序,该函数接收 2 个参数,代表需要排序的 2 个数组元素。会修改原数组。如果函数返回负值或 0,元素顺序保持不变,返回正值,对调元素位置。

let arr = [1, 7, 3, -1, 5, 7, 2];
const sorter = (firstEl, secondEl) => firstEl - secondEl;
arr.sort(sorter);
console.log(arr);
// [-1, 1, 2, 3, 5, 7, 7]

你是否已经全部理解了呢?我还没有。事实上,我在写这篇文章的时候也经常参考 MDN 文档——没关系!只要知道有什么样的方法就可以了。

7. Generators

不要害怕*。生成器函数指定了下次调用next()时会迭代什么值。可以进行有限次数的迭代,也可以在循环中进行无限次数的迭代。

function* greeter() {
yield ‘Hi’;
yield ‘How are you?’;
yield ‘Bye’;
}
const greet = greeter();
console.log(greet.next().value);
// ‘Hi’
console.log(greet.next().value);
// ‘How are you?’
console.log(greet.next().value);
// ‘Bye’
console.log(greet.next().value);
// undefined

无限迭代:

function* idCreator() {
let i = 0;
while (true) yield i++;
}
const ids = idCreator();
console.log(ids.next().value);
// 0
console.log(ids.next().value);
// 1
console.log(ids.next().value);
// 2
// etc…

8. === VS ==

确信你已经了解了===与==的差异。在进行比较时,==会进行类型转换,===则不会。

console.log(0 == ‘0’);
// true
console.log(0 === ‘0’);
// false

9. 比较对象

一个 javascript 新手常犯的错误就是直接比较对象。变量指向对象在内存中的引用,而不是对象本身。比较变量的一个方法是将它们转换为 JSON 字符串。当然这样会有缺点:不能保证对象属性的顺序。更安全的方式是使用第三方库中专用的比较方法来比较(lodash.isEqual)。 下面的对象看着是一样的,但其实它们指向不同的引用。

const joe1 = { name: ‘Joe’ };
const joe2 = { name: ‘Joe’ };
console.log(joe1 === joe2);
// false

反过来说,下面的比较结果为 true,因为变量被直接赋值为相同的值,都指向同一个引用(在内存中只有一个对象)。

const joe1 = { name: ‘Joe’ };
const joe2 = joe1;
console.log(joe1 === joe2);
// true

复习下之前的值 VS 引用章节,保证能完全理解将一个引用变量赋值给其他变量时,其实是赋值了内存中同一对象的相同引用给其他变量。

10. 回调函数

许多人都会被 javascript 的回调函数吓到!其他它们很简单,来看例子。console.log作为回调函数传递给了myFunc。当计时器就绪时执行。

function myFunc(text, callback) {
setTimeout(function() {
callback(text);
}, 2000);
}
myFunc(‘Hello world!’, console.log);
// ‘Hello world!’

11. Promises

一旦你理解的回调函数,你就会陷入回调地狱。然后 Promises 解决了问题。在 Promise 中包裹你的异步逻辑,成功时调用 resolve,失败时调用 reject。使用 then 来处理成功状态,使用 catch 来处理异常状态。

const myPromise = new Promise(function(res, rej) {
setTimeout(function() {
if (Math.random() < 0.9) {
return res(‘Hooray!’);
}
return rej(‘Oh no!’);
}, 1000);
});

myPromise
.then(function(data) {
console.log(‘Success: ‘ + data);
})
.catch(function(err) {
console.log(‘Error: ‘ + err);
});

// If Math.random() returns less than 0.9 the following is logged:
// “Success: Hooray!”
// If Math.random() returns 0.9 or greater the following is logged:
// “Error: On no!”

12. Async Await

一旦你掌握了 Promises,你就会喜欢async/await,它是基于 promises 的语法糖。下面的例子中我们使用了 async 函数,在函数里使用了 await 来处理greeter。

const greeter = new Promise((res, rej) => {
setTimeout(() => res(‘Hello world!’), 2000);
});
async function myFunc() {
const greeting = await greeter;
console.log(greeting);
}
myFunc();
// ‘Hello world!’

结语

如果你还不了解这 12 个概念,你可能已经至少增长了一些 javascript 的知识。如果你已经了解了这些,希望这是你练习和加强知识的机会。 文章来源:12 Concepts That Will Level Up Your JavaScript Skills

想要设置区域分割线颜色首先要知道他的属性是什么,splitLine 顾名思义”分割线”。知道了分割线是什么属性后我来看看他都包含哪些特性。 从API中可以看出他是坐标轴xAxisyAxis中的一个splitLine:{} 对象,证明他的内部有多个属性和值。我们以X轴为例

splitLine: {
show: true,
interval: ‘auto’,
lineStyle: {
color: [‘#ccc’],
width: 1,
type: ‘solid’,
shadowBlur: …,
shadowColor: …,
shadowOffsetX: 0,
shadowOffsetY: 0,
opacity: …,
}
}

xAxis.splitLine.show      boolean 值 [ default: true ] 是否显示分隔线。默认数值轴显示,类目轴不显示。 xAxis.splitLine.interval   number, Function [ default: ‘auto’ ] 坐标轴分隔线的显示间隔,在类目轴中有效。默认同 axisLabel.interval 一样。 默认会采用标签不重叠的策略间隔显示标签。 可以设置成 0 强制显示所有标签。 如果设置为 1,表示『隔一个标签显示一个标签』,如果值为 2,表示隔两个标签显示一个标签,以此类推。 可以用数值表示间隔的数据,也可以通过回调函数控制。回调函数格式如下: (index:number, value: string) => boolean 第一个参数是类目的 index,第二个值是类目名称,如果跳过则返回 false。 xAxis.splitLine.lineStyle      Object

xAxis.splitLine.lineStyle.**color**      Array, string

[ default: [‘#ccc’] ] 分隔线颜色,可以设置成单个颜色。 也可以设置成颜色数组,分隔线会按数组中颜色的顺序依次循环设置颜色。 示例

splitLine: {
lineStyle: {
// 使用深浅的间隔色
color: [‘#aaa’, ‘#ddd’]
}
}

xAxis.splitLine.lineStyle.**width**      number

[ default: 1 ] 分隔线线宽。

xAxis.splitLine.lineStyle.**type**      string

[ default: ‘solid’ ] 分隔线线的类型。 可选:

  • 'solid'
  • 'dashed'
  • 'dotted'

xAxis.splitLine.lineStyle.**shadowBlur**      number

图形阴影的模糊大小。该属性配合 shadowColor,shadowOffsetX, shadowOffsetY一起设置图形的阴影效果。 示例:

{
shadowColor: ‘rgba(0, 0, 0, 0.5)’,
shadowBlur: 10
}

xAxis.splitLine.lineStyle.**shadowColor**      Color

阴影颜色。支持的格式同color。

xAxis.splitLine.lineStyle.**shadowOffsetX**      number

[ default: 0 ] 阴影水平方向上的偏移距离。

xAxis.splitLine.lineStyle.**shadowOffsetY**      number

[ default: 0 ] 阴影垂直方向上的偏移距离。

xAxis.splitLine.lineStyle.**opacity**      number

图形透明度。支持从 0 到 1 的数字,为 0 时不绘制该图形。 通过上面的解释我们可以了解到坐标轴区域的分割线可以设置 分割线颜色、分割线大小、分割线类型、分割线阴影以及分割线的透明度

See the Pen Echarts设置坐标轴区域中的分隔线颜色 by w3cbest.com (@w3cbest) on CodePen.

CSS 变量混合使用加法减法

当设置一个变量为200px时后期不满足需求需要增加10px或20px时而需要扩展; 例如我们需要给一个div的宽度设置为210px,但我们的变量是200px,这时我们就可以用变量的值加上10px就行了,如下 (本篇所使用的宽度属性是CSS逻辑属性

:root{
–base-size-200: 200px;
}

div{
inline-size: calc(var(–base-size-200) + 10px);
}

或者我们的变量里面已经有10px这个变量了,那么可以这样做

:root{
–base-size-200: 200px;
–base-size-10: 10px;
}

div{
inline-size: calc(var(–base-size-200) + var(–base-size-10));
}

如果的话减法同上面一样,就是把加号换做减号就行了

div{
inline-size: calc(var(–base-size-200) - var(–base-size-10));
}

CSS 变量混合使用乘法除法

乘法就是把你现在大小乘以你想要的值就是你的尺寸,我们还以上面的为例,将200px设为2倍或3倍来运算

:root{
–base-size-200: 200px;
}

div{
inline-size: calc(var(–base-size-200) * 2);
}

除法同上面一样将乘号换为除号

div{
inline-size: calc(var(–base-size-200) / 2);
}

CSS 变量加法与乘法混合使用

其实这个也很简但,就是将上面的两种方法加起来运算就可以了

:root{
–base-size-200: 200px;
–base-size-10: 10px;
}
div{
inline-size: calc(var(–base-size-200) * 2 + var(–base-size-10));
}

好了全是废话,篇幅较小不喜勿喷

CKEDITOR网页编辑器还是挺复杂的,有一个 CKEDITOR 的全局空间,有一个 CKEDITOR.instances的全局实例引用,有 Classic 编辑和 Inline 编辑两种模式,有 Plugin 也有 Widget,有自成一体的编译打包工具,与 AMD\CMD\UMD社区不兼容。

加载

生成编辑器

经典编辑(Classic Editing)

内嵌编辑(Inline Editing)

按钮面板定制(Toolbar)

一组一组定义

config.toolbarGroups = [
{ name: ‘clipboard’, groups: [ ‘clipboard’, ‘undo’ ] },
{ name: ‘editing’, groups: [ ‘find’, ‘selection’, ‘spellchecker’ ] },
{ name: ‘links’ },
{ name: ‘insert’ },
{ name: ‘forms’ },
{ name: ‘tools’ },
{ name: ‘document’, groups: [ ‘mode’, ‘document’, ‘doctools’ ] },
{ name: ‘others’ },
‘/‘,
{ name: ‘basicstyles’, groups: [ ‘basicstyles’, ‘cleanup’ ] },
{ name: ‘paragraph’, groups: [ ‘list’, ‘indent’, ‘blocks’, ‘align’, ‘bidi’ ] },
{ name: ‘styles’ },
{ name: ‘colors’ },
{ name: ‘about’ }
];

一个一个定义

config.toolbar = [
{ name: ‘document’, items: [ ‘Source’, ‘-‘, ‘NewPage’, ‘Preview’, ‘-‘, ‘Templates’ ] },
{ name: ‘clipboard’, items: [ ‘Cut’, ‘Copy’, ‘Paste’, ‘PasteText’, ‘PasteFromWord’, ‘-‘, ‘Undo’, ‘Redo’ ] },
‘/‘,
{ name: ‘basicstyles’, items: [ ‘Bold’, ‘Italic’ ] }
];

插件机制

假如我们开发一个插入当前时间戳的插件

插件目录结构

  • ckeditor root/
    • plugins/
      • timestamp/
        • icons/
          • timestamp.png
        • plugin.js

插件代码

CKEDITOR.plugins.add(‘timestamp’, {
icons: ‘timestamp’,
init: function(editor) {
editor.addCommand(‘insertTimestamp’, {
exec: function(editor) {
var now = new Date();
editor.insertHtml(‘The current date and time is: ‘ + now.toString() + ‘‘);
}
});
editor.ui.addButton(‘Timestamp’, {
label: ‘Insert Timestamp’,
command: ‘insertTimestamp’,
toolbar: ‘insert’
});
}
});

通过 CKEDITOR.plugins.add方法添加插件,第一个参数为插件名,后面为参数列表。 通过editor.addCommand方法添加一个 insertTimestamp 的命令 通过editor.ui.addButton方法添加一个按钮控件,并绑定其执行的 command 通过 editor.insertHtml方法往编辑内容区域追加内容

加载插件

通过配置文件来开启插件

config.extraPlugins = ‘timestamp’;

如果这是一个会出现在 Toolbar 的插件,且 Toolbar 被定制过,则需要显性配置 toolbar让其显示

config.toolbar = {
{name: ‘insert’, [‘Timestamp’]}
}

挂件(Widget)

挂件是由一组 html 元素组成的特殊富文本单元,类似于模板机制 与插件的区别 挂件有 template 字段,插件没有 挂件目录结构 与插件一致

挂件代码

CKEDITOR.plugins.add( ‘simplebox’, {

// 表明这是一个 widget
requires: ‘widget’,

icons: 'simplebox',

init: function( editor ) {
    CKEDITOR.dialog.add( 'simplebox', this.path + 'dialogs/simplebox.js' );

    editor.widgets.add( 'simplebox', {

   // 鼠标 hover 在 toolbar 上出现的提示
        button: 'Create a simple box',

        // 挂件模板
        template:
            '<div class="simplebox">' +
                '<h2 class="simplebox-title">Title</h2>' +
                '<div class="simplebox-content"><p>Content...</p></div>' +
            '</div>',

        // 定义挂件中可编辑的部分
        editables: {
            title: {
                selector: '.simplebox-title',
                allowedContent: 'br strong em'
            },
            content: {
                selector: '.simplebox-content',
                allowedContent: 'p br ul ol li strong em'
            }
        },

        // 挂件内允许出现的组合
        allowedContent:
            'div(!simplebox,align-left,align-right,align-center){width};' +
            'div(!simplebox-content); h2(!simplebox-title)',

        // 挂件最小组合,如果这个 div 被删除,则自动清除该挂件
        requiredContent: 'div(simplebox)',

        dialog: 'simplebox',

        upcast: function( element ) {
            return element.name \== 'div' && element.hasClass( 'simplebox' );
        },

        init: function() {
            var width \= this.element.getStyle( 'width' );
            if ( width )
                this.setData( 'width', width );
            if ( this.element.hasClass( 'align-left' ) )
                this.setData( 'align', 'left' );
            if ( this.element.hasClass( 'align-right' ) )
                this.setData( 'align', 'right' );
            if ( this.element.hasClass( 'align-center' ) )
                this.setData( 'align', 'center' );
        },

        data: function() {

            if ( this.data.width \== '' )
                this.element.removeStyle( 'width' );
            else
                this.element.setStyle( 'width', this.data.width );

            this.element.removeClass( 'align-left' );
            this.element.removeClass( 'align-right' );
            this.element.removeClass( 'align-center' );
            if ( this.data.align )
                this.element.addClass( 'align-' + this.data.align );
        }
    } );
}

} );

ACF

CKEditor 的高级内容过滤器,当用户在源码输入模式、editor.setData输入、直接粘贴 html 代码等输入时候,将不希望出现的内容给过滤掉。

自动模式(Automatic Mode)

config.allowedContent 没有设置的时候,ACF 就会进入自动模式。 自动模式通过config.removePluginsconfig.removeButtonsconfig.format_tag 来做过滤微调

config.removePlugins = ‘image,table,tabletools,horizontalrule’;
config.removeButtons = ‘Anchor,Underline,Strike,Subscript,Superscript’;
config.format_tags = ‘p;h1;h2;pre’;

自定义模式(Custom Mode)

通过 config.allowedContent 来进入自定义模式

config.allowedContent =
‘h1 h2 h3 p blockquote strong em;’ +
‘a[!href];’ +
‘img(left,right)[!src,alt,width,height];’;

ACF语法

elements [attributes]{styles}(classes)

例如我们需要保留这样的富文本内容,规则为span(mod_fillblank),其 attributes 对 class 无效。

实战建议

  • 能用 CKEditor 社区插件解决的问题,用插件解决
  • 插件解决不了的问题,业务自己写plugin 或者 widget 解决
  • 业务自己写的部分,尽量不要用 CKEditor 自带的 CKEDITOR.dialog ,他们的实现是用 JS 去码DOM 结构,太复杂了。随便一个 Dialog 控件都能用得很舒服
  • 不要用CKEditor 的 jQuery Adapter,他家的 Adapter 对于同一个 DOM 的进行实例化、销毁等操作有 bug,时不时给你冒一个错误。自己包裹一个 Adapter 则肯定没有 bug
  • 工程化的时候,构建工具做依赖分析的时候,记得排除掉 CKEditor 目录,否则他家一堆的插件,会严重拖慢依赖分析那步

前言

本文主要从应用来讲数组api的一些骚操作; 如一行代码扁平化n维数组、数组去重、求数组最大值、数组求和、排序、对象和数组的转化等; 上面这些应用场景你可以用一行代码实现?

1.扁平化n维数组

1.终极篇

[1,[2,3]].flat(2) //[1,2,3]
[1,[2,3,[4,5]].flat(3) //[1,2,3,4,5]
[1,[2,3,[4,5]]].toString() //‘1,2,3,4,5’
[1[2,3,[4,5[…]].flat(Infinity) //[1,2,3,4…n]

Array.flat(n)是ES10扁平数组的api,n表示维度,n值为Infinity时维度为无限大

2.开始篇

function flatten(arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(…arr);
}
return arr;
}
flatten([1, [2, 3]]) //[1,2,3]
flatten([1, [2, 3, [4, 5]]) //[1,2,3,4,5]

实质是利用递归和数组合并方法concat实现扁平

2.去重

1.终极篇

Array.from(new Set([1,2,3,3,4,4])) //[1,2,3,4]
[…new Set([1,2,3,3,4,4])] //[1,2,3,4]

set是ES6新出来的一种一种定义不重复数组的数据类型 Array.from是将类数组转化为数组 ...是扩展运算符,将set里面的值转化为字符串

2.开始篇

Array.prototype.distinct = function() {
var arr = this,
result = [],
i,
j,
len = arr.length;
for (i = 0; i < len; i++) {
for (j = i + 1; j < len; j++) {
if (arr[i] === arr[j]) {
j = ++i;
}
}
result.push(arr[i]);
}
return result;
}
[1, 2, 3, 3, 4, 4].distinct(); //[1,2,3,4]

取新数组存值,循环两个数组值相比较

3.排序

1.终极篇

[1,2,3,4].sort((a, b) => a - b); // [1, 2,3,4],默认是升序
[1,2,3,4].sort((a, b) => b - a); // [4,3,2,1] 降序

sort是js内置的排序方法,参数为一个函数

2.开始篇

冒泡排序:

Array.prototype.bubleSort = function() {
let arr = this,
len = arr.length;
for (let outer = len; outer >= 2; outer–) {
for (let inner = 0; inner <= outer - 1; inner++) {
if (arr[inner] > arr[inner + 1]) {
//升序
[arr[inner], arr[inner + 1]] = [arr[inner + 1], arr[inner]];
console.log([arr[inner], arr[inner + 1]]);
}
}
}
return arr;
}
[1, 2, 3, 4].bubleSort() //[1,2,3,4]

选择排序

Array.prototype.selectSort = function() {
let arr = this,
len = arr.length;
for (let i = 0, len = arr.length; i < len; i++) {
for (let j = i, len = arr.length; j < len; j++) {
if (arr[i] > arr[j]) {
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
}
return arr;
}
[1, 2, 3, 4].selectSort() //[1,2,3,4]

4.最大值

1.终极篇

Math.max(…[1, 2, 3, 4]) //4
Math.max.apply(this, [1, 2, 3, 4]) //4
[1, 2, 3, 4].reduce((prev, cur, curIndex, arr) => {
return Math.max(prev, cur);
}, 0) //4

Math.max()是Math对象内置的方法,参数是字符串; reduce是ES5的数组api,参数有函数和默认初始值; 函数有四个参数

  • pre(上一次的返回值)
  • cur(当前值)
  • curIndex(当前值索引)
  • arr(当前数组)

2.开始篇

先排序再取值

5.求和

1.终极篇

[1, 2, 3, 4].arr.reduce(function(prev, cur){
return prev + cur;
}, 0) //10

2.开始篇

function sum(arr) {
var len = arr.length;
if (len == 0) {
return 0;
} else if (len == 1) {
return arr[0];
} else {
return arr[0] + sum(arr.slice(1));
}
}
sum([1,2,3,4]) //10

利用slice截取改变数组,再利用递归求和

6.合并

1.终极篇

[1,2,3,4].concat([5,6]) //[1,2,3,4,5,6]
[…[1,2,3,4],…[4,5]] //[1,2,3,4,5,6]
[1,2,3,4].push.apply([1,2,3,4],[5,6]) //[1,2,3,4,5,6]

2.开始篇

let arr = [1, 2, 3, 4];
[5, 6].map(item => {
arr.push(item)
})
//arr值为[1,2,3,4,5,6],注意不能直接return出来,return后只会返回[5,6]

7.判断是否包含值

1.终极篇

[1,2,3].includes(4) //false
[1,2,3].indexOf(4) //-1 如果存在换回索引
[1, 2, 3].find((item)=>item===3)) //3 如果数组中无值返回undefined
[1, 2, 3].findIndex((item)=>item===3)) //2 如果数组中无值返回-1

includes(),find(),findIndex()是ES6的api

2.开始篇

[1, 2, 3].some(item =>{
return item === 3
}) //true 如果不包含返回false

8.类数组转化

1.终极篇

Array.prototype.slice.call(arguments) //arguments是类数组(伪数组)
Array.prototype.slice.apply(arguments)
Array.from(arguments)
[…arguments]

类数组:表示有length属性,但是不具备数组的方法 call,apply:是改变slice里面的this指向arguments,所以arguments也可调用数组的方法 Array.from是将类似数组或可迭代对象创建为数组 ...是将类数组扩展为字符串,再定义为数组

2.开始篇

Array.prototype.slice = function(start, end) {
var result = new Array();
start = start 0;
end = end this.length; //this指向调用的对象,当用了call后,能够改变this的指向,也就是指向传进来的对象,这是关键
for (var i = start; i < end; i++) {
result.push(this[i]);
}
return result;
}

9.每一项设置值

1.终极篇

[1,2,3].fill(false) //[false,false,false]

fill是ES6的方法

2.开始篇

[1,2,3].map(() => 0)

10.每一项是否满足

[1,2,3].every(item=>{return item>2}) //false

every是ES5的api,每一项满足返回 true

11.有一项满足

[1,2,3].some(item=>{return item>2}) //true

some是ES5的api,有一项满足返回 true

12.过滤数组

[1,2,3].filter(item=>{return item>2}) //[3]

filter是ES5的api,返回满足添加的项的数组

13.对象和数组转化

Object.keys({name:’张三’,age:14}) //[‘name’,’age’]
Object.values({name:’张三’,age:14}) //[‘张三’,14]
Object.entries({name:’张三’,age:14}) //[[name,’张三’],[age,14]]
Object.fromEntries([name,’张三’],[age,14]) //ES10的api,Chrome不支持 , firebox输出{name:’张三’,age:14}

文章来源:https://segmentfault.com

在 Web 开发中,有许多情况需要解析 URL,这篇主要学习如何使用 URL 对象实现这一点。 入门 创建一个以下内容的 HTML 文件,并在浏览器中打开。

JavaScript URL parsing

如果你想尝试本文中的任何内容,可以将其放在