官方文档 https://ant.design/components...
目录
一、antd中的Grid
目录
- 整体思路
- less文件结构图(♦♦♦重要)
- less实现逻辑图(♦♦♦重要)
- 源码节选:antd/components/grid/style/mixin.less
- 源码节选:antd/components/grid/col.tsx
没有使用React 底层基础组件。Grid的特点在于css样式的控制,本次着重对css结构进行了梳理代码目录
1、整体实现思路
col
less负责生成 ant-col-1 到 ant-col-24 的样式
组件tsx中负责根据父组件传入的props属性,生成自己使用的class名称
row
处理不同size下处理整行宽度
处理间距gutter
2、css文件结构图
3、col中less实现逻辑图
4、源码节选:antd/components/grid/style/mixin.less
5、源码节选:antd/components/grid/col.tsx
二、其他源码解读
目录
1.responsiveObserve.js解读
- row.js解读
1、responsiveObserve.js文件
Window matchMedia() 方法的基本使用
matchMedia() 返回一个新的 MediaQueryList 对象,表示指定的媒体查询字符串解析后的结果。
语法
window.matchMedia(mediaQueryString)
mediaQueryString: 必需,一个字符串,表示即将返回一个新 MediaQueryList 对象的媒体查询。
matchMedia() 方法的值可以是任何一个 CSS @media 规则 的特性, 如 min-height, min-width, orientation 等。
MediaQueryList 对象的属性和方法
属性:
media:查询语句的内容。
alert(window.matchMedia("(max-width:100px)").media); //(max-width: 100px)
matches:用于检测查询结果,如果文档匹配 media query 列表,值为 true,否则为 false。
方法:
addListener(_functionref_)
添加一个新的监听器函数,该函数在媒体查询的结果发生变化时执行。
removeListener(_functionref_)
从媒体查询列表中删除之前添加的监听器。 如果指定的监听器不在列表中,则不执行任何操作。
实例
判断屏幕(screen/viewport)窗口大小:
if (window.matchMedia("(max-width: 700px)").matches) {
/* 窗口小于或等于 700 像素 */
} else {
/*窗口大于 700 像素 */
}
判断屏幕(screen/viewport)窗口大小,在小于等于 700 像素时修改背景颜色为黄色,大于 700 像素时修改背景颜色为粉红色:
function myFunction(x) {
if (x.matches) {
// 媒体查询
document.body.style.backgroundColor = "yellow";
} else {
document.body.style.backgroundColor = "pink";
}
}
var x = window.matchMedia("(max-width: 700px)")
myFunction(x) // 执行时调用的监听函数
x.addListener(myFunction) // 状态改变时添加监听器
可选链操作符( ?.
)的基本使用(https://wiki.developer.mozill...
可选链操作符(?.
)允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。?.
操作符的功能类似于.
链式操作符,不同之处在于,在引用为空(nullish ) (null
或者undefined
) 的情况下不会引起错误,该表达式短路返回值是undefined
。与函数调用一起使用时,如果给定的函数不存在,则返回undefined
。当尝试访问可能不存在的对象属性时,可选链操作符将会使表达式更短、更简明。在探索一个对象的内容时,如果不能确定哪些属性必定存在,可选链操作符也是很有帮助的。
原理
比如,思考一个存在嵌套结构的对象 obj
。不使用可选链的话,查找一个深度嵌套的子属性时,需要验证之间的引用,例如:
let nestedProp = obj.first && obj.first.second;
为了避免报错,在访问obj.first.second
之前,要保证 obj.first
的值既不是 null
,也不是 undefined
。如果只是直接访问 obj.first.second
,而不对 obj.first
进行校验,则有可能抛出错误。
有了可选链操作符(?.
),在访问 obj.first.second
之前,不再需要明确地校验 obj.first
的状态,再并用短路计算获取最终结果:
let nestedProp = obj.first?.second;
通过使用 ?.
操作符取代 .
操作符,JavaScript 会在尝试访问 obj.first.second
之前,先隐式地检查并确定 obj.first
既不是 null
也不是 undefined
。如果obj.first
是 null
或者 undefined
,表达式将会短路计算直接返回 undefined
。
这等价于以下表达式,但实际上没有创建临时变量:
let temp = obj.first;
let nestedProp = ((temp === null || temp === undefined) ? undefined : temp.second);
实例
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
};
const dogName = adventurer.dog?.name;
console.log(dogName);
// expected output: undefined
console.log(adventurer.someNonExistentMethod?.());
// expected output: undefined
2、row.js文件
(1)官网上的可传参数
(2)源码详解
classNames的基本用法
classNames是一个简单的js实用插件,它的主要用例之一是使动态和条件className
道具更易于使用(尤其是比条件字符串操作更简单)。使用时它将导出classNames方法,该函数接受任意数量的参数,这些参数可以是 字符串 或 对象 。
classNames (' foo ',' bar ') ; // =>'foo bar'
classNames (' foo ',{ bar :true } ) ; // =>'foo bar'
classNames ({ ' foo-bar ':true } ) ; // =>'foo-bar'
classNames ({ ' foo-bar ':false } ) ; // =>''
classNames ({ foo :true } ,{ bar :true } ) ; // =>'foo bar'
classNames ({ foo :true , bar :true } ) ; // =>'foo bar'
// 许多不同类型的参数
classNames (' foo ',{ bar :true , duck :false } ,' baz ',{ quux :true } ) ; // =>'foo bar baz quux'
// 其他虚假值将被忽略
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
结合es6的模板语法使用(gird组件中多用)
let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true });
代码中的 Partial<> 和 Record<> 都是ts里面的内置类型
1.keyof
keyof
与Object.keys
略有相似,只不过keyof
取interface
的键。
interface Point { x: number; y: number; }
type keys = keyof Point; // type keys = "x" | "y"
用例:
假设有一个object
如下所示,我们需要使用typescript
实现一个get
函数来获取它的属性值。
一般情况下,我们会这样写:
const data = {
a: 3,
hello: 'world'
}
function get(o: object, name: string) {
return o[name]
}
但这样有几个缺点
1.无法确定返回类型:这将损失ts最大的类型校验功能
2.无法对key
做约束:可能会拼写错误
3.可做修改达到类型约束,但不够简洁
这时可以使用 keyof
来加强 get
函数的类型功能
function get<T extends object,k extends keyof T>(o:T,name:K):T[k]{
return o[name]
}
2.partial
keyof T
拿到T
所有属性名, 然后in
进行遍历, 将值赋给P
, 最后T[P]
取> > 得相应属性的值.
type Partial<T> = {
[P in keyof T]?: T[P];
};
例子:
interface People {name: string}
// 变为
Partial<People> => {name?: string}
其是有局限性的,只能处理一层
interface People {
name: string;
person: {name: string; name1: string}
}
type NewPeople = Partial<People>
// error: Property 'name1' is missing in type ...
const jack: NewPeople = {
name: 'jack',
person: {
name: 'son'
}
}
// 如何解决呢 递归
type PowerPartial<T> = {
[U in keyof T]?: T[U] extends object
? PowerPartial<T[U]>
: T[U]
};
3.record
标记对象的 key value类型
type Record<K extends keyof any, T> = {
[P in K]: T;
};
例子:
const user: Record<'name'|'email', string> = {
name: '',
email: ''
}
// 复杂一点
function mapObject<K extends string | number, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>;
// 这里简易实现,否则报ts(2391)错误
function mapObject(): any {}
const names = { foo: "hello", bar: "world", baz: "bye" };
const lengths = mapObject(names, s => s.length);
type newNames = typeof lengths // => { foo: number, bar: number, baz: number }
4.pick
这个类型则可以将某个类型中的子属性挑出来,变成包含这个类型部分属性的子类型。
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
例子:
interface User { id: number; age: number; name: string; };
// 相当于: type PickUser = { id: number; age: number; }
type PickUser = Pick<User, "id" | "age">
类型保护和类型断言
由于可以为null的类型是通过联合类型实现,那么你需要使用类型保护来去除 null
。 幸运地是这与在JavaScript里写的代码一致:
function f(sn: string | null): string {
if (sn == null) {
return "default";
}
else {
return sn;
}
}
这里很明显地去除了 null
,你也可以使用短路运算符:
function f(sn: string | null): string {
return sn || "default";
}
如果编译器不能够去除 null
或 undefined
,你可以使用类型断言手动去除。 语法是添加 !
后缀: identifier!
从 identifier
的类型里去除了 null
和 undefined
:
function broken(name: string | null): string {
function postfix(epithet: string) {
return name.charAt(0) + '. the ' + epithet; // error, 'name' is possibly null
}
name = name || "Bob";
return postfix("great");
}
function fixed(name: string | null): string {
function postfix(epithet: string) {
return name!.charAt(0) + '. the ' + epithet; // ok
}
name = name || "Bob";
return postfix("great");
}
本例使用了嵌套函数,因为编译器无法去除嵌套函数的null(除非是立即调用的函数表达式)。 因为它无法跟踪所有对嵌套函数的调用,尤其是你将内层函数做为外层函数的返回值。 如果无法知道函数在哪里被调用,就无法知道调用时 name
的类型。