0%

replace

常规用法

1
2
str.replace('_','')
str.replace(/[^0-9a-zA-Z]/g,"");

指定函数作为参数
即第二个参数为函数
见于hexo源码 /node_modules/hexo/lib/hexo/post.js line 42, line 25
1
2
3
4
5
6
7
8
9
restoreCodeBlocks(str) {
return str.replace(rCodeBlockPlaceHolder, _restoreContent(this.cache));
}
const _restoreContent = cache => (_, index) => {
assert(cache[index]);
const value = cache[index];
cache[index] = null;
return value;
};

rCodeBlockPlaceHolder是一串正则表达式,replace对str中符合正则表达式的结果(即str.match(rCodeBlockPlaceHolder))应用参数二方法,方法执行结果替换相应的字符串
值得注意的是,_restoreContent(this.cache)返回一个带迭代的方法,index对应str.match(rCodeBlockPlaceHolder)的次序

数据结构——图

各元素之间有路径 如a1 -> a2, a2 -> a4, a3 -> a1

根据路径的指向 给每个元素统计入度出度

例 寻找小镇法官问题

题解即求是否存在入度为n出度为0的节点

例 课程表问题:该学期必须选修 numCourses 门课程 课程存在的前置关系数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi]

约定俗成地,用两个节点对表示图上的有向路径 某节点有多条路径 在图关系列表中 就有多项 包含该节点元素

题解思路 入度为0的课程xi可直接选 以xi为前置的课程随后可选 以此类推 可选课程等于 numCourses 即可完成学期课程任务

数据结构——堆(heap)

数据结构中的堆是完全二叉树(从上到下、从左到右连续性) 通常依序以长列表的形式存储在计算机中

若以1~n为序号 任意i∈n节点 左右子节点分别是2i,2i+1

堆排序 就是将数据整理成大根堆(根节点均大于等于子节点)或小根堆(根节点均小于等于子节点),js并不像C++、Java等面向对象语言提供了堆结构的Api, 堆排的js实现复杂 手写容易出错。且记堆排序时间复杂度O(nlogK)

对于形似堆结构的题目 退而求其次使用sort api和循环计数的方式完成

应用场景如 top K问题:找出数组中最大/小的count个数

桶排序问题

堆型数据结构的问题 有时可以用桶排序的方式解。 所谓桶排序 就是将项放到某集合中 通过对集合进行排序 筛选出解

如 返回前k高频元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 桶排
var createBucket = (nums)=>{
// value - frequency Map
const map = new Map()
nums.forEach(val=>{
if(map.get(val)){
map.set(val, map.get(val)+1)
}else{
map.set(val,1)
}
})
//console.log('map:',map)
return map
}
var topKFrequent = function(nums, k) {
const map = createBucket(nums)
const arr = [] // 相同频次(freq)的value 归并到一起 作为arr的一项 该项放到arr的下标为req的位置
const res = []
map.forEach((freq,key)=>{
if(arr[freq]){
arr[freq].push(key)
}else{
arr[freq] = [key]
}
})
//console.log('arr:',arr)
for(i=arr.length-1;i>=0&&res.length<k;i--){
if(arr[i]){
res.push(...arr[i])
}
}
return res
}

数据结构——栈

数据结构——队列

数据结构——链表

至少两部分:数据域&指针域 链表没有索引 查找复杂度O(n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Node(){
constructor(data){
this.data = data
this.next = null
}
}

const head = new Node(1)
head.next = new Node(2)

// 输出链表
let point = head
let res = ''
while(point){ // 若链表有环 循环不会停止
res+=`${point.data}->`
point = point.next
}
console.log(res)

检查链表是否有环

  • 节点放入集合(如Set)遍历中利用Set.has(point)检查是否存在此节点对象

  • 快慢指针 遍历环时必会套圈 无环则快指针先跳出循环

1
2
3
4
5
6
7
8
9
10
11
fast = head
slow = head
while(fast && fast.next){
slow = slow.next
fast = fast.next.next

if(fast === slow){
return true
}
}
return false

双向链表 克服单向链表逆序查找困难的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Snode{
constructor(val,next = null){
this.data = val
this.next = next
}
}
class Dnode{
constructor(val, perv = null, next = null){
this.data = val
this.next = next
this.prev = perv
}
}
// test case
let head = new Snode(null)
let node = head
for(let val of [1,2,3,4,5]){
console.log(val)
node.next = new Snode(val)
node = node.next
}
head = head.next
// constructed test case

const dhead = new Dnode(head.data)
let point = head
let dpoint = dhead
while(point.next){
dpoint.next = new Dnode(point.next.data, dpoint, null)

point = point.next
dpoint = dpoint.next
}
console.log(dhead)

数据结构——数组

数据结构——矩阵

数据结构——字符串

数据结构——哈希表

数据结构——二叉树

遍历顺序(前、中、后)指的是根节点在遍历时的先后顺序 均为递归遍历 深度优先

二叉树的广度优先遍历(层序遍历)

算法——广度优先搜索(BFS)

算法——深度优先搜索(DFS)

算法——滑动窗口

滑动窗口本质是双指针问题 一 在一个游标(指针)基础上 移动另一个游标 判断符合条件 然后分情况移动左右游标

三数之和

数组中任意三数之和 与目标数值最接近的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function nearThreeSumary(arr, target) {
arr.sort((a, b) => (a - b))
let distance = Number.MAX_VALUE
res = []
for (let i = 0; i < arr.length-3; i++) {
let left = i + 1
let right = arr.length - 1
while (left < right) {
const sum = arr[i] + arr[left] + arr[right]
if (Math.abs(target - sum) < distance)
res = [arr[i], arr[left], arr[right]]
distance = target - sum
console.log([arr[i], arr[left], arr[right]], sum)
if (target > sum) {
left++
} else if (target < sum) {
right--
} else {
return res
}
}
}
return res
}

两数之和的问题利用的就是left right双指针,三数之和的问题是在两数之和基础上固定一个。

算法——动态规划(DP)

爬楼梯问题被称为动态规划

统计一步两步上楼方式 f(n) = f(n-1) + f(n-2)只是个简单的迭代方法

每级台阶设上权重 即爬楼梯最小开支问题

整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用(起点和终点不在数组中)。你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

下面是个错误题解!迭代较大数组时计算开销激增 甚至测试用例运行超时

1
2
3
4
5
6
7
8
9
var minCostClimbingStairs = function(cost) {
if(cost.length<=1) return 0

// up1
const pay1 = minCostClimbingStairs(cost.slice(0,cost.length-1)) + cost[cost.length-1]
// up2
const pay2 = minCostClimbingStairs(cost.slice(0,cost.length-2)) + cost[cost.length-2]
return Math.min(pay1,pay2)
};

事实上 return f(n-1) + f(n-2) 的代码在统计上楼方式时已经存在问题 如下统计f(5)时,f(3)重复计算(称为重叠子) 当迭代层级增大时重复计算以指数激增

1
2
3
4
5
6
7
        f(5)
/ \
f(4) f(3)
/ \ / \
f(3) f(2) f(2) f(1)
/ \
f(2) f(1)

为避免重复计算 要自低阶到高阶 将已经计算的结果(应称为子问题最优解或最优子,并非局部最优解)缓存起来

1
2
3
4
5
6
7
8
9
var minCostClimbingStairs = function(cost) {
const dp = []
dp[0] = 0
dp[1] = 0
for(let i=2;i<=cost.length;i++){
dp[i] = Math.min(dp[i-1] + cost[i-1], dp[i-2]+ cost[i-2])
}
return dp[cost.length]
};

f(n) = f(n-1) + f(n-2) 斐波那契数列

算法——二分查找

典型的复杂度O(logN)的算法

算法——双指针

快慢指针

对向指针

算法——并查集

算法——位运算

算法——分治

快排的本质也是分治

返回第k大的数 数组值范围大 要求O(n)复杂度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function findKmax(nums, k){

quickSort(nums, 0, nums.length-1)
function quickSort(nums, left, right){
// 枢轴
const pivot = nums.length-1
quickSort()
}

function patition(arr, left, right){
const pivot = Math.floor(Math.random()*(right - left +1 ) + left)
let i = left, j = right
while(i<=j){
while(arr[i]<arr[pivot]) {
i++
}
while(arr[j]>arr[pivot]){
j--
}
if(i<=j){
[arr[i],arr[j]] = [arr[j], arr[i]]
}
}
return i
}
}

算法——回溯

算法——贪心

算法——递归

算法——数学

Progressing Web Application
https://create-react-app.dev/docs/making-a-progressive-web-app/
https://web.dev/progressive-web-apps/

渐进式意使是网站根据浏览器的功能相应地呈现,高级的浏览器呈现高级的效果。就目前来看主要表现是对于版本比较高的 chrome,firefox 等浏览器,pwa 可以使用 add to home screen 的功能,使网络应用固定在桌面、移动设备主屏幕,成为独立应用

脱机使用的渐进式web应用更快速也更可靠,还具备更吸引人的移动端体验,比如在网络不佳的场景下使用,还有添加到主屏幕的功能

网络应用清单 manifest.json

参考PWA manifest 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
"short_name": "MY APP",
"name": "MY APP Full Name",
"icons": [
{
"src": "icon/lowres.webp",
"sizes": "48x48",
"type": "image/webp"
},{
"src": "icon/lowres",
"sizes": "48x48"
},{
"src": "icon/hd_hi.ico",
"sizes": "72x72 96x96 128x128 256x256"
},{
"src": "icon/hd_hi.svg",
"sizes": "257x257"
}
],
"start_url": "/",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#FFB71B",
"url": "/",
"manifestUrl": "/manifest.json",
"lang": "en",
"description": "blabla",
"scope": "."
}

manifest的生成可以借助webpack plugin生成

Service Worker

Service Worker 是一直在浏览器后台运行的worker线程,设置其拦截用户的请求(如加载脚本和图片)进而可以改变请求行为,如不访问服务器直接返回, 再如从缓存加载资源 以提升在离线或加载繁重的应用场景

如下注册Service Worker,Service Worker必须由HTTPS协议载入,Service Worker脚本须与网站同域

1
2
3
4
5
6
7
8
9
if ('serviceWorker' in navigator) {
// register service worker
navigator.serviceWorker.register('./sw.js', {scope: './'}) // 参数1:注册提供的脚本URL 参数2:导航匹配
.then(()=>{
console.log('注册成功')
}).catch(()=>{
console.log('注册失败')
});
}

sw.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 缓存静态文件
self.addEventListener('install', (event) => {
event.waitUntil(caches.open('myapp').then((cache) => cache.addAll(['**/*'])));
});

// 缓存接口数据
self.addEventListener('fetch', (event) => {
event.respondWith(caches.match(event.request).then((response) => {
// 匹配到请求
if (response !== undefined) {
return response;
} else {
return fetch(event.request).then((response) => {
// 缓存响应数据
let responseClone = response.clone();
caches.open('v1').then((cache) => {
cache.put(event.request, responseClone);
});
return response;
}).catch(() => {
return caches.match('/gallery/myLittleVader.jpg');
});
}
}));
});

// 更新缓存
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
// 如果有更新
if (cacheName !== 'v1') {
return caches.delete(cacheName);
}
})
);
}).then(function(){
return self.clients.claim()
})
);
});

Service Worker生命周期:

如index.html中 加载应用时即注册service worker,注册成功即触发安装事件(install event),见sw.js代码,在安装事件的响应中,处理应用缓存

安装成功后激活service worker触发激活事件(active event)

激活成功后service worker进入idle状态 在该状态下所有请求会触发fetch event 直到应用关闭

Service Worker的更新:

触发更新

  • 导航到作用域内页面时
  • 某事件触发后24h未下载Service Worker

若Service Worker下载后被发现是新文件,无论Service Worker内容是否与现有的相同,都将触发install

如果是第一次安装Service Worker,如上所述安装成功后触发激活,但对于更新,Service Worker已启用的情形,会等待所有已加载的页面不再依赖旧的Service Worker后,触发激活

添加到主屏幕(a2hs)

使应用支持a2hs:

  • https
  • 正确配置的manifest.json
  • 合适的图标
  • 注册service worker
    注册service worker是作为a2hs条件的,但是可以a2hs,未必可以离线使用

框架支持

react pwa

1
npx create-react-app my-app --template cra-template-pwa

安装

1
2
yarn add react-intl
yarn add -D @formatjs/ts-transformer

we highly recommend declaring defaultMessages inline along with their usages because of the following reasons: 建议使用声明内联的defaultMessages, 连同他们的usage,原因如下

  1. Messages colocated with their usages become self-managed, as their usages change/removed, so are the messages. 搭配usage的Message成为自治的 当usage更改或移除,Message亦同
  2. Messages are highly contextual. We’ve seen a lot of cases where developers assume a certain grammar when they write their messages. Buttons/Call-To-Actions and labels are also translated differently. Message高度关联上下文, 杜绝为message发明新语法或编规则
  3. Text styling is also dependent on the message itself. Things like truncation, capitalization… certainly affect the messages themselves. 会与样式相关
  4. Better integrations with toolchains. Most toolchains cannot verify cross-file references to validate syntax/usage. 易于工具链集成

格式化语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import * as React from 'react'
import {IntlProvider, FormattedMessage, FormattedNumber} from 'react-intl'

<IntlProvider messages={messagesInFrench} locale="fr" defaultLocale="en">
<p>
<FormattedMessage
id="myMessage"
defaultMessage="Today is {ts, date, ::yyyyMMdd}"
values={{ts: Date.now()}}
/>
<br />
<FormattedNumber value={19} style="currency" currency="EUR" />
</p>
</IntlProvider>

Error: [React Intl] Could not find required ‘intl’ object. IntlProvider needs to exist in the component ancestry

当没有IntlProvider父组件时报上述异常

提取文本映射

1
yarn add -D @formatjs/cli

package.json中添加脚本命令

1
"extract": "formatjs extract"

执行
1
2
3
yarn extract 'src/**/*.ts*' --out-file lang/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'

npm run extract -- 'src/**/*.ts*' --out-file lang/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'

将待翻译的message保存为指定语言的json文件,没id的message自动编码id

分发

将翻译好的多语言lang/*.json编译为Intl使用的格式
package.json中添加脚本命令

1
"compile": "formatjs compile"

执行
1
2
3
yarn compile lang/fr.json --ast --out-file compiled-lang/fr.json

npm run compile -- lang/fr.json --ast --out-file compiled-lang/fr.json

切换语言代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import {IntlProvider} from 'react-intl'

function loadLocaleData(locale: string) {
switch (locale) {
case 'fr':
return import('compiled-lang/fr.json')
default:
return import('compiled-lang/en.json')
}
}

function App(props) {
return (
<IntlProvider
locale={props.locale}
defaultLocale="en"
messages={props.messages}
>
<MainApp />
</IntlProvider>
)
}

async function bootstrapApplication(locale, mainDiv) {
const messages = await loadLocaleData(locale)
ReactDOM.render(<App locale={locale} messages={messages} />, mainDiv)
}

切换语言触发IntlProvider下的组件初始化,将本地化的messages词条传入组件上下文

useIntl钩子

返回当前语言的provider对象,提供formatData,formatMessage等方法,从messages词条中映射字符串

1
2
3
4
5
6
const intl = useIntl()
return (
<span title={intl.formatDate(date)}>
<FormattedDate value={date} />
</span>
)

带参数的格式化Message
1
2
3
4
5
6
7
8
9
dragAreaSupportTip(format: string) {
const messages = defineMessages({
supportTip: {
id: 'dragArea.supportTip',
defaultMessage: 'Only supports {format} files',
},
})
return intl.formatMessage(messages.supportTip, { format });
}

formatjs extract和compile命令可以在此使用
switch case 场景
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
translateEnums(name:string){
name = name.replace(/ /g, '_')
const messages = defineMessages({
transName: {
id: 'enums.name',
defaultMessage: `{name, select,
dog {dog}
cat {cat}
King_Kong {King Kong}
other {{name}}
}`,
},
})
const translatedName = this.intl.formatMessage(messages.transName, { name:name });
return translatedName.replace(/_/g, ' ')
}

格式是{key, select, 选项..}的样子,见format.js Doc:select format 选项是’value {text}的格式,value据说遵循Unicode Pattern_Syntax 然而我并没有找到空格的表示法,如上’金刚’的名字用下划线替换了空格,另外匹配失败返回原字符串,变量key需再加大括号括起来

参考https://www.cnblogs.com/dreamroute/p/8484457.html

全文搜索引擎

‘全文检索’不是ElasticSearch,ElasticSearch是一个开源的基于全文搜索引擎(Apache Lucene)的搜索和分析引擎。

全文搜索引擎面向文档型存储,即插入其数据库的每条记录作为一个文档,搜索引擎为提取文档的词,生成索引,通过查询索引达到搜索目标文档的目的。这种先建立索引,再对索引进行搜索的过程就叫全文检索(Full-text Search)

文档-类型-索引

关系数据库: ⇒ 数据库 ⇒ 表 ⇒ 行 ⇒ 列(Columns)

Elasticsearch: ⇒ 索引(Index) ⇒ 类型(type) ⇒ 文档(Docments) ⇒ 字段(Fields)

二叉树 倒排

Kibana

ElasticSearch的可视化仪表盘

Philosophy

湖是水源汇聚之处

Azure Data Lake includes all the capabilities required to make it easy for developers, data scientists, and analysts to store data of any size, shape, and speed, and do all types of processing and analytics across platforms and languages. It removes the complexities of ingesting(插入) and storing all of your data while making it faster to get up and running with batch(批量), streaming, and interactive analytics. ———— Azure Data Lake Solution

Material UI System

System是Material UI 自定义主题、样式的一套方法
依赖

1
npm install @material-ui/system@next @emotion/react @emotion/styled

  • 直接就可以在你需要的组件上面进行样式定制
  • 避免定义一些列的样式(className)或带样式组件(styled-component)
  • 制定统一的标准 如字体 字号 色系

关于使用sx系统样式与定义styled-component的书写差异
styled-component

1
2
3
4
5
6
7
8
9
10
const StatHeader = styled('div')(z
({ theme }) => `
color: blue;
`,
);

...
return (
<StatHeader>font color is blue here</StatHeader>
)

‘轻’组件(Box, Stack, Typography, and Grid) 和 sx属性
1
2
3
4

return (
<Box sx={{ color: 'text.secondary' }}>this color is blue here</Box>
)

Material Design

Material Design

Color Palette tool
一套以上述工具生成的颜色模板(基于#36b0c9)👇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$qqs-design:(
50: #e7f6f9,
100: #c3e7ef,
200: #9bd8e4,
300: #72c8d9,
400: #54bcd1,
500: #36b0c9,
600: #30a9c3,
700: #29a0bc,
800: #2297b5,
900: #1687a9,
A100: #dcf6ff,
A200: #a9e9ff,
A400: #76ddff,
A700: #5dd6ff,
contrast: (
50: #262626,
100: #262626,
200: #262626,
300: white,
400: white,
500: white,
600: white,
A100: #262626,
A200: white,
A400: white,
A700: white
)
);

material套用自定义颜色模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Custom Theming for Angular Material
// For more information: https://material.angular.io/guide/theming
@import '~@angular/material/theming';
// Plus imports for other components in your app.
@import 'theme.scss';
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat-core();

// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue. Available color palettes: https://material.io/design/color/
$CSDPartnerPortal-primary: mat-palette($csd2021);
$CSDPartnerPortal-accent: mat-palette($csd2021, 500, A100, A400);

// The warn palette is optional (defaults to red).
$CSDPartnerPortal-warn: mat-palette($mat-red);

// Create the theme object. A theme consists of configurations for individual
// theming systems such as "color" or "typography".
$CSDPartnerPortal-theme: mat-light-theme((
color: (
primary: $CSDPartnerPortal-primary,
accent: $CSDPartnerPortal-accent,
warn: $CSDPartnerPortal-warn,
)
));

// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include angular-material-theme($CSDPartnerPortal-theme);

如果说flex适合做一维(水平或竖直放向)元素的布局,那么grid就是做二维布局的,如字面意思,grid布局将平面划分成 m*n 的网格,子元素分布其中,以所处/所占的行和列的控制实现页面layout的划分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<div class="wrapper">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
<div class="four">Four</div>
<div class="five">Five</div>
<div class="six">Six</div>
</div>
<style>
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
grid-auto-rows: minmax(100px, auto);
}
.one {
grid-column: 1 / 3;
grid-row: 1;
}
.two {
grid-column: 2 / 4;
grid-row: 1 / 3;
}
.three {
grid-row: 2 / 5;
grid-column: 1;
}
.four {
grid-column: 3;
grid-row: 3;
}
.five {
grid-column: 2;
grid-row: 4;
}
.six {
grid-column: 3;
grid-row: 4;
}
</style>

display: grid 或 inline-grid区分整个区域是否作为行内元素插入,不影响区域内的grid

列划分:

1
2
3
grid-template-columns: 200px 500px 100px;
grid-template-columns: repeat(4, 25%);
grid-template-columns: 200px repeat(3, 1fr) 100px;

注:fr是grid的特殊单位,可以从总分列去掉固定宽度列后均分剩余列
行划分grid-template-rows类似,也可以按比例划分剩余宽度

间距:

1
2
3
grid-gap: 5px;
grid-row-gap: 5px;
grid-column-gap: 5px;

填充:

1
grid-template-columns: repeat(auto-fill, 200px);

以200px为一列,根据区域宽度调整列数(响应式)

区间:

1
grid-template-columns: 1fr 1fr minmax(300px, 2fr)

第三个列宽最少也是要 300px,但是最大不能大于第一第二列宽的两倍。

区域定义:(略)

流:

1
2
3
grid-auto-flow: row;
grid-auto-flow: row dense;
grid-auto-flow: column;

填充单元格的横纵顺序,如果遇到尺寸不够而挤到下一行的情况,dense可以使用合适的子元素填充前面的空余单元格

对齐:
justify-item, align-item:父容器配置,分别控制子元素在所处单元格空间的对齐方向,两者默认是stretch撑满空间
可选值:start center end stretch

justify-content, align-content:父容器配置,分别控制整个grid(父容器)在上层容器中的对齐方向,两者默认是start

justify-self, align-self:子元素配置,控制自身在所处单元格空间的对齐方向与*-item一致

隐式网格:
在超出grid-template-columns和grid-template-rows的定义之后应用的网格划分

1
2
3
grid-template-columns: 200px 500px 100px;
grid-template-rows: 100px 100px;
grid-auto-rows: 50px;

指定坐标:

1
2
3
4
5
6
.item {
grid-column-start: 3;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 4;
}

svg 可缩放矢量图形(Scalable Vector Graphics), 使用xml格式定义图形,大概长这样子

1
2
3
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
</svg>

嵌入html中可以作为dom操作,在数据可视化入门中曾提到D3数据可视化库即使用svg进行动态渲染的

对于简单的icon响应可以有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<style>
.toggle-btn {
display: inline-block;
width: 40px;
height: 40px;
cursor: pointer;
color: #000;
background: #ccc;
}

.toggle-btn>input {
width: 0;
height: 0;
opacity: 0;
}

.toggle-btn>svg {
width: 100%;
height: 100%;
}

input:checked+svg circle {
fill: blue
}
</style>
<label class="toggle-btn">
<input type="checkbox">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<circle cx="20" cy="20" r="20" stroke="black" stroke-width="2" fill="none" />
</svg>
</label>

svg-react-loader

将.svg文件资源作为组件载入

1
2
3
import MyIcon from '-!svg-react-loader!../../assets/image/icon.svg'
...
return (<> <MyIcon> <>)

作为资源路径
1
2
3
import MyIcon from '../../assets/image/icon.svg'
...
return (<img src={MyIcon} />)

作为inline element(原生React特性)
1
2
3
4
5
import {ReactComponent as MyIcon} from '../../assets/image/icon.svg'
...
return (<div style={{color:'red', cursor: 'pointer'}}>
<MyIcon />
</div>)

ng-inline-svg

shared.module.ts

1
2
3
4
5
6
7
8
9
10
import { InlineSVGModule } from 'ng-inline-svg'

@NgModule({
imports: [...LibModules,
InlineSVGModule.forRoot()],
exports: [...MuiModules],
declarations: [],
providers: [],
})
export class SharedModule { }

mycomponent.html
1
<div [inlineSVG]="'assets/image/icon.svg'"></div>

鼠标响应

Web MDN: svg pointer-events

async await写一个训练过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
async function practise() {
console.log('训练开始...')
let result;
result = await warmup(2)
if(result) console.log('热身完成。。')
result = await squat(5)
if(result) console.log('深蹲完成。。')
result = await boating(3)
if(result) console.log('划船完成。。')
}

function warmup(time){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, time*1000);
});
}

function squat(time){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, time*1000);
});
}

function boating(time){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, time*1000);
});
}

// 执行这个‘训练’
practise().then(res=>{
console.log('完了')
})

从输出结果上看,特点是按照顺序逐步完成某动作,似乎本身就是一个generator
于是把每个动作装到一个generator里
1
2
3
4
5
function* practisePlan() {
yield warmup(2)
yield squat(5)
yield boating(3)
}

yield返回的是一个promise,promise ‘resolve’的情况下才会 ‘next’
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let practise = function () {
return new Promise((resolve, reject)=>{
const plan = practisePlan()
Promise.resolve(plan.next().value).then(result=>{
if(result) console.log('热身完成。。')
return plan.next().value;
}).then(result=>{
if(result) console.log('深蹲完成。。')
return plan.next().value;
}).then(result=>{
if(result) console.log('划船完成。。')
resolve() // <--完了
})
})
}

再看循环中的async await的栗子 —-> S-为什么说 async/await是generator的语法糖?