antd源码分析 gird

朴一

官方文档 https://ant.design/components...

目录

一、antd中的Grid

目录

  1. 整体思路
  2. less文件结构图(♦♦♦重要)
  3. less实现逻辑图(♦♦♦重要)
  4. 源码节选:antd/components/grid/style/mixin.less
  5. 源码节选: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解读

  1. row.js解读

1、responsiveObserve.js文件

image.png
image.png

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) // 状态改变时添加监听器

image.png

可选链操作符( ?. )的基本使用(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.firstnull 或者 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)源码详解

image.png

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 });

image.png

代码中的 Partial<>Record<> 都是ts里面的内置类型

1.keyof

keyofObject.keys 略有相似,只不过 keyofinterface 的键。

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"> 

image.png

类型保护和类型断言

由于可以为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";
}

如果编译器不能够去除 nullundefined,你可以使用类型断言手动去除。 语法是添加 !后缀: identifier!identifier的类型里去除了 nullundefined

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的类型。

阅读 25
1 声望
0 粉丝
0 条评论
1 声望
0 粉丝
宣传栏