木偶's Blog

如果发现能力无法支撑自己的野心,那就静下心来学习吧

Linux运维书单推荐

操作系统

  • 深⼊入理理解计算机系统
  • 计算机是怎么跑起来的
  • 程序是怎么跑起来的

网络协议

TCP/IP协议详解卷一:协议

http权威指南

图解TCP/IP

Linux

  • 鸟哥的Linux私房菜
  • Linux命令行与shell脚本编程⼤大全
  • Linux内核设计的艺术(关于内核,难度较大)

数据库

  • 深入浅出 MySQL 数据库
  • MySQL技术内幕:InnoDB存储引擎
  • Redis开发与运维

编程语言

  • python核心编程(Python)
  • C Primer Plus(C语言)

云计算&虚拟化

  • Docker技术入门与实战
  • Kubernetes权威指南

网站架构

  • 大型网站技术架构 核心原理理与案例例分析

image.png

1.1 CDN加速是什么?

CDN 全称 Content Delivery Network,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。

通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN 系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决 Internet 网络拥挤的状况,提高用户访问网站的响应速度。

CND 加速主要是加速静态资源,如网站上面上传的图片、媒体,以及引入的一些 Js、css 等文件。

CND 加速需要依靠各个网络节点,例如 100 台 CDN 服务器分布在全国范围,从上海访问,会从最近的节点返回资源,这是核心。

CND 服务器通过缓存或者主动抓取主服务器的内容来实现资源储备。

简单得来说,CDN 的作用就是,当我们向服务器请求某些资源 (例如静态资源),哪个服务器最快最稳定,我们就去哪个服务器获取。同时 CDN 的成本也比较低

1.2 为什么要使用CDN

如果你在经营一家网站,那你应该知道几点因素是你制胜的关键:

内容有吸引力 访问速度快 支持频繁的用户互动 可以在各处浏览无障碍

另外,你的网站必须能在复杂的网络环境下运行,考虑到全球的用户访问体验。你的网站也会随着使用越来越多的对象 (如图片、帧、CSS 及 APIs ) 和形形色色的动作 (分享、跟踪) 而系统逐渐庞大。所以,系统变慢带来用户的流失。

1.3 常见CDN服务器

  • 自己的 CDN 服务器:在阿里云、腾讯云、华为云、Google、亚马逊等都可以购买到。
  • 开源的 CDN 服务器:例如 unpkg、JSDelivr、cdnjs

创业团队

目的在于形成一个完整的闭环团队,形成一个小型但又完整的创业团队。

  • 运维
  • 运营
  • 开发
  • 市场
  • 培训:黑马、中睿(提供企业的 IT 服务)

企业发展过程中,还需要对企业的数据进行管理、形成数据资产、获取更多的经济利益。

1.1 前端处理

通常,我们前端在开发管理后台的时候,会选择 vue+element 这样的技术栈去实现。但我们后端给的数据格式通常并不符合 element 的参数数据要求。比如,级联选择器 cascader 的参数数据格式如下:

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
[{
"label": "第一级",
"value": 2,
"children": [{
"label": "第二级",
"value": 4,
"children": [{
"label": "第三级",
"value": 13
}, {
"label": "测试3",
"value": 14
}]
}]
}, {
"label": "2",
"value": 3,
"children": [{
"label": "4",
"value": 5
}]
}, {
"label": "测试分类2",
"value": 11,
"children": [{
"label": "测试分类0",
"value": 12,
"children": [{
"label": "测试分类3",
"value": 15
}]
}]
}]

而我们后端在输出接口的时候,是极少采用这种数据格式的。比如,一般叫 id|name|child 这样的字段名。

我们知道,cascader 是支持这样的别名参数设计的,因此我们使用时也没什么问题。

但是我今天遇到的一个状况是,后端直接给出了一个一维数组,换句话说,这位兄弟是直接查了一下数据表,把所有的数据通过一个数组直接给我返回了。而至于我怎么使用这个数据,他就不考虑了,因为他还有其他业务需要开发。

后端返回的数据格式如下:

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
[{
"catid": 2,
"parentId": 0,
"catname": "第一级",
}, {
"catid": 3,
"parentId": 0,
"catname": "2",
}, {
"catid": 4,
"parentId": 2,
"catname": "第二级",
}, {
"catid": 5,
"parentId": 3,
"catname": "4",
}, {
"catid": 12,
"parentId": 11,
"catname": "测试分类0",
}, {
"catid": 11,
"parentId": 0,
"catname": "测试分类2",
}, {
"catid": 13,
"parentId": 4,
"catname": "第三级",
}, {
"catid": 14,
"parentId": 4,
"catname": "测试3",
}, {
"catid": 15,
"parentId": 12,
"catname": "测试分类3",
}]

嗯,理解。不就是个简单的递归嘛!我一会儿就写好了。但我担心后面其他地方还有这样类似的接口输出,那我总是写递归不就很麻烦了吗?因此,将此方法抽离,并加了一些扩展,最终方法代码如下:

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
export const makeElementTree = (params) => {
// 将参数拿出来,不喜欢 params.xxx 的调用方式
const { pid, list, pidFiled, labelFiled, valueFiled } = params
// 构建一个内部函数,用于实现递归
const makeTree = (pid, arr) => {
const res = []
arr.forEach(i => {
if (i[pidFiled] === pid) {
// 自己调用自己,递归查归属于自己的 children
const children = makeTree(i[valueFiled], list)
// 将原有的数据按照 element 的格式进行重构
const obj = {
label: i[labelFiled],
value: i[valueFiled]
}
// 如果有 children 则插入 obj 中
if (children.length) {
obj.children = children
}
res.push(obj)
}
})
return res
}
return makeTree(pid, list)
}

在业务代码中,我们首先引入我们的方法,然后传进去参数就可以啦,如下演示:

1
2
3
4
5
6
7
8
const treeCats = makeElementTree({
pid: 0, // 顶级分类的 pid 为 0
list: data, // 将原始数组参数穿进去
pidFiled: 'parentId', // 在数组对象中,pid 字段名为 parentId
labelFiled: 'catname',// 我们想要的 label 字段名为 catname
valueFiled: 'catid' // 我们想要的 value 字段名为 catid
})
console.log(treeCats)

1.2 后端数据处理

如果是后端直接处理后返回,则递归如下:

1
2
3
4
5
6
7
8
9
10
def makeTree(pid, arr):
res = []
for i in arr:
if i['pid'] == pid:
rep = makeTree(i['id'], arr)
if len(rep) != 0:
i['children'] = rep
res.append(i)
return res
res = makeTree(0, sourceList)

最后,在编程中,慎用递归!!!

HTML 页面部分

1
2
3
4
5
6
7
<el-form-item label="时间" prop="testDate">
<el-date-picker
v-model="testDate"
tyep="daterange"
start-placeholde="开始日期"
end-placeholde="结束日期" />
</el-form-item>

JavaScript 部分

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
export default {
data() {
startTime = '',
endTime = ''
....
}
....
computed: {
testDate: {
get() {
return [this.startTime, this.endTime]
},
set(val) {
// 此处需要对 val 进行判空,因为 el-date-picker 的清空按钮点击之后会将 testDate 置为 null
if (val) {
this.startTime = dateFormate(val[0])
this.endTime = dateFormate(val[0])
} else {
this.startTime = ''
this.endTime = ''
}
}
}
}
method: {
reset() {
this.startTime = ''
this.endTime = ''
}
}
}

Cascader级联选择器出现空面板的问题

vue、element、el-element

image-20210617122750695

出现空白面板是因为树形结构的数据的最底层 children 是个空数组。遇到这种问题,前端可以通过递归,将 children 长度为 0 的节点对象的 children 属性删除,或将值赋为 undefined

1
2
3
4
5
6
7
cleanData(itemList) {  // 将根节点的 children 传入,传入的只是数据对象的引用
for (const item of itemList) {
if (item.children.length === 0) delete item.children
else this.cleanData(item.children)
}
return itemList
}

vue 允许将按键值作为修饰符来使用,如监听回车事件,有两种写法,如下代码:

1
2
<input type="text" @keyup.13="console.log($event)"></input>
<input type="text" @keyup.enter="console.log($event)"></input>

当我们在 el-input 采用如上两种写法时,他是不生效的。el-input 监听不到键盘事件,原因是 element-ui 是封装组件,所以 el 标签属于自定义标签,因此触发不了键盘事件。

解决办法 :加上 .native 原生事件修饰符即可。

.native:监听组件根元素的原生事件,主要作用是给自定义的组件添加原生事件。vue 与 elementUI 中给 el-input 绑定键盘按键代码如下:

1
2
3
4
5
6
7
<el-input 
placeholder="店铺名称"
clearable
v-model="queryObj.shopname"
@keyup.enter.native="query">
<template slot="prepend">店铺名称</template>
</el-input>

解决van-dialog内容过多却没有滚动样式的问题

场景

通过组件调用 Dialog 时,van-dialog 内嵌套其他组件,其内容过多,Dialog 不会自动出现滚动样式,导致无法显示底部按钮

image-20210708143224495

解决方案

在样式中做如下设置

1
2
3
4
/deep/ .van-dialog__content {
max-height: 400px;
overflow: scroll;
}

说明:先设置最大行高,然后再给溢出部分设置 scroll 滚动样式。

1.1 背景描述

  • 操作系统:macOS
  • 通过 npm 全局安装的 yarn

1.2 问题描述

通过命令 yarn global add packageName 后,试图该模块的命令,发现无法找到

image-20210930135631984

1.3 问题分析

macOS 在安装完 npm 后,再通过 npm 安装 yarn。则 yarn 相关配置和包路径默认位于家目录下

image-20210930135818676

通过 yarn global add 安装包,则会被安装到 ~/.config/yarn/global/node_modules/

image-20210930140102368

而该路径是没有配置在环境变量中的,因此无法找到。

1.4 解决方案

将上述路径配置到环境变量中即可。此处我是配置在 ~/.zshrc 中,大家可以视自身所用的 shell 自行决定。

配置如下:

image-20210930140654119

1
export PATH="$PATH:`yarn global bin`:$HOME/.config/yarn/global/node_modules/.bin"

配置后保存,执行 source ./.zshrc

结果如下:

image-20210930140835904
0%