Button
Button包括了兩個(gè)組件,Button與ButtonGroup。
ButtonProps看一個(gè)組件首先看的是他的傳參也就是props,所以我們這里先看Button組件的ButtonProps
export type ButtonType = "primary" | "ghost" | "dashed" | "danger"; export type ButtonShape = "circle" | "circle-outline"; export type ButtonSize = "small" | "large"; // typescript語(yǔ)法,這里表示的是一些參數(shù),參數(shù)后面跟上 ? 是可選參數(shù)的意思,不跟就是必須參數(shù) // 參數(shù)后面所跟的就是參數(shù)的類型,類型可以是自定義的類型,就如‘ButtonType’,‘ButtonShape’,‘ButtonSize’ // 也可以是函數(shù)或者類,如React.FormEventHandlerRender()// 詳情請(qǐng)看這里 https://www.tslang.cn/docs/handbook/interfaces.html export interface ButtonProps { type?: ButtonType; htmlType?: string; icon?: string; shape?: ButtonShape; size?: ButtonSize; onClick?: React.FormEventHandler ; onMouseUp?: React.FormEventHandler ; onMouseDown?: React.FormEventHandler ; loading?: boolean | { delay?: number }; disabled?: boolean; style?: React.CSSProperties; prefixCls?: string; className?: string; ghost?: boolean; }
看完其參數(shù)有哪些之后我們就直接跳過(guò)組件內(nèi)部的其他的東西,直接看他的渲染函數(shù),畢竟這里是執(zhí)行的入口
這里順帶提一下這句代碼
// 這里的意思是將傳入兩個(gè)參數(shù),React.Component的參數(shù)第一個(gè)是Props,第二個(gè)是state, // 然后利用typescript的類型檢查,Props類型需要時(shí)上面定義的ButtonProps中的可選參數(shù)中的變量名 // state這里傳入任意都行 export default class Button extends React.Component
// 接下來(lái)是render() render() { // 將參數(shù)從props解構(gòu)出來(lái) const { type, shape, size = "", className, htmlType, children, icon, prefixCls, ghost, ...others, } = this.props; // 將loading和clicked兩個(gè)狀態(tài)從state解構(gòu) const { loading, clicked } = this.state; // large => lg // small => sm let sizeCls = ""; switch (size) { case "large": sizeCls = "lg"; break; case "small": sizeCls = "sm"; default: break; } // 組建樣式 const classes = classNames(prefixCls, className, { [`${prefixCls}-${type}`]: type, [`${prefixCls}-${shape}`]: shape, [`${prefixCls}-${sizeCls}`]: sizeCls, [`${prefixCls}-icon-only`]: !children && icon, [`${prefixCls}-loading`]: loading, [`${prefixCls}-clicked`]: clicked, [`${prefixCls}-background-ghost`]: ghost, }); // 是否需要加載 const iconType = loading ? "loading" : icon; // 是否需要添加Icon,不過(guò)官方給的是如果需要用到icon的話最好自己寫在里面 const iconNode = iconType ?InsertSpace(): null; const needInserted = React.Children.count(children) === 1 && (!iconType || iconType === "loading"); // 重點(diǎn)在這里,敲黑板了 // 這里引用了React.Children.map這個(gè)函數(shù)來(lái)對(duì)這個(gè)包裹在這個(gè)Button組件中的內(nèi)容渲染出來(lái) // 其中insertSpace()這個(gè)函數(shù)也有意思,這個(gè)函數(shù)主要是為了在當(dāng)組建中間寫的是中文漢字的時(shí) // 候給其漢字之間添加一個(gè)空格作為分隔,這里有的同學(xué)會(huì)問(wèn)為什么不用css里面的letter-space // 屬性,這個(gè)我也不是很清楚。。。不過(guò)他不用的話可能是是不想在英文字母中間添加空格吧 const kids = React.Children.map(children, child => insertSpace(child, needInserted)); return ( ); }
上面講到了這個(gè)函數(shù),這里就來(lái)仔細(xì)看看是干嘛的吧
const rxTwoCNChar = /^[u4e00-u9fa5]{2}$/;
// 這里的bind有必要好好的理解一下
const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar);
function isString(str: any) {
return typeof str === "string";
}
// Insert one space between two chinese characters automatically.
function insertSpace(child: React.ReactChild, needInserted: boolean) {
// Check the child if is undefined or null.
if (child == null) {
return;
}
const SPACE = needInserted ? " " : "";
// strictNullChecks oops.
// 這個(gè)判斷的意思是當(dāng)這個(gè)child不是字符串也不是數(shù)字并且child.type為字符串并且child的children是漢字的情況下
// 給其加上空格,上面說(shuō)的是代碼直譯,那么代碼意譯下來(lái)就是這樣的一個(gè)情況
// 這種情況(所以這里他才會(huì)有一個(gè)英文注釋,說(shuō)的是不是嚴(yán)格意義的檢查,啊哈哈,尷尬的實(shí)現(xiàn)方法)
//
// 這里說(shuō)明一下,child.type以及child.props.children是react在渲染的時(shí)候會(huì)給虛擬dom添加的一些屬性,如圖
if (typeof child !== "string" && typeof child !== "number" &&
isString(child.type) && isTwoCNChar(child.props.children)) {
return React.cloneElement(child, {},
child.props.children.split("").join(SPACE));
}
// 這種情況就很明了了 就是Button組件中寫的漢字
if (typeof child === "string") {
if (isTwoCNChar(child)) {
child = child.split("").join(SPACE);
}
return {child};
}
return child;
}
完整源代碼
剩下的都是一些簡(jiǎn)單的東西,也沒有什么可以講的了
import React from "react"; import PropTypes from "prop-types"; import classNames from "classnames"; import omit from "omit.js"; import Icon from "../icon"; import Group from "./button-group"; const rxTwoCNChar = /^[u4e00-u9fa5]{2}$/; const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar); function isString(str: any) { return typeof str === "string"; } // Insert one space between two chinese characters automatically. function insertSpace(child: React.ReactChild, needInserted: boolean) { // Check the child if is undefined or null. if (child == null) { return; } const SPACE = needInserted ? " " : ""; // strictNullChecks oops. if (typeof child !== "string" && typeof child !== "number" && isString(child.type) && isTwoCNChar(child.props.children)) { return React.cloneElement(child, {}, child.props.children.split("").join(SPACE)); } if (typeof child === "string") { if (isTwoCNChar(child)) { child = child.split("").join(SPACE); } return {child}; } return child; } export type ButtonType = "primary" | "ghost" | "dashed" | "danger"; export type ButtonShape = "circle" | "circle-outline"; export type ButtonSize = "small" | "large"; export interface ButtonProps { type?: ButtonType; htmlType?: string; icon?: string; shape?: ButtonShape; size?: ButtonSize; onClick?: React.FormEventHandler; onMouseUp?: React.FormEventHandler ; onMouseDown?: React.FormEventHandler ; loading?: boolean | { delay?: number }; disabled?: boolean; style?: React.CSSProperties; prefixCls?: string; className?: string; ghost?: boolean; } export default class Button extends React.Component { // 這里這樣子寫只是為了方便這樣子寫B(tài)utton.Group來(lái)引用ButtonGroup這個(gè)組件,下一節(jié)將會(huì)講解這個(gè)組件 static Group: typeof Group; static __ANT_BUTTON = true; static defaultProps = { prefixCls: "ant-btn", loading: false, clicked: false, ghost: false, }; static propTypes = { type: PropTypes.string, shape: PropTypes.oneOf(["circle", "circle-outline"]), size: PropTypes.oneOf(["large", "default", "small"]), htmlType: PropTypes.oneOf(["submit", "button", "reset"]), onClick: PropTypes.func, loading: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]), className: PropTypes.string, icon: PropTypes.string, }; timeout: number; delayTimeout: number; constructor(props: ButtonProps) { super(props); this.state = { loading: props.loading, }; } componentWillReceiveProps(nextProps: ButtonProps) { const currentLoading = this.props.loading; const loading = nextProps.loading; if (currentLoading) { clearTimeout(this.delayTimeout); } if (typeof loading !== "boolean" && loading && loading.delay) { this.delayTimeout = setTimeout(() => this.setState({ loading }), loading.delay); } else { this.setState({ loading }); } } // 在組件銷毀的時(shí)候一定要記得將定時(shí)器也一同銷毀 componentWillUnmount() { if (this.timeout) { clearTimeout(this.timeout); } if (this.delayTimeout) { clearTimeout(this.delayTimeout); } } handleClick = (e: React.MouseEvent ) => { // Add click effect this.setState({ clicked: true }); clearTimeout(this.timeout); this.timeout = setTimeout(() => this.setState({ clicked: false }), 500); const onClick = this.props.onClick; if (onClick) { onClick(e); } } render() { const { type, shape, size = "", className, htmlType, children, icon, prefixCls, ghost, ...others, } = this.props; const { loading, clicked } = this.state; // large => lg // small => sm let sizeCls = ""; switch (size) { case "large": sizeCls = "lg"; break; case "small": sizeCls = "sm"; default: break; } const classes = classNames(prefixCls, className, { [`${prefixCls}-${type}`]: type, [`${prefixCls}-${shape}`]: shape, [`${prefixCls}-${sizeCls}`]: sizeCls, [`${prefixCls}-icon-only`]: !children && icon, [`${prefixCls}-loading`]: loading, [`${prefixCls}-clicked`]: clicked, [`${prefixCls}-background-ghost`]: ghost, }); const iconType = loading ? "loading" : icon; const iconNode = iconType ? : null; const needInserted = React.Children.count(children) === 1 && (!iconType || iconType === "loading"); const kids = React.Children.map(children, child => insertSpace(child, needInserted)); return ( ); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/89015.html
摘要:作為開發(fā)當(dāng)中使用相對(duì)頻繁的一個(gè)組件,其實(shí)現(xiàn)也很簡(jiǎn)單,但是其中比較麻煩的一部分是字體的制作,可以參看這篇文章。接口中的種屬性方法,不屬于上述六種。為事件屬性,可以大家也可以根據(jù)上面所提供的制作的方法和這樣的方式來(lái)實(shí)現(xiàn)自己的組件 Icon icon作為開發(fā)當(dāng)中使用相對(duì)頻繁的一個(gè)組件,其實(shí)現(xiàn)也很簡(jiǎn)單,但是其中比較麻煩的一部分是icon字體的制作,可以參看這篇文章。 Antd的Icon組件使用...
github: 地址gitbook: 地址 Index.js 看一個(gè)代碼的時(shí)候首先當(dāng)然是從他的入口文件開始看起,所以第一份代碼我們看的是/index.js文件 開始 打開index.js文件,代碼只有28行,其中包含了一個(gè)camelCase函數(shù)(看函數(shù)名就知道這是個(gè)給名稱進(jìn)行駝峰命名法的函數(shù)),一個(gè)req變量,以及這個(gè)的變量操作和export操作 在這個(gè)文件里面我首先查了require.conte...
摘要:結(jié)構(gòu)項(xiàng)目結(jié)構(gòu)如下,負(fù)責(zé)外層封裝,負(fù)責(zé)事件綁定與渲染控制。節(jié)點(diǎn)通過(guò)決定事件綁定情況,即通過(guò)屬性綁定事件情況,事件控制組件的屬性,這里就不詳細(xì)說(shuō)了。為隱藏狀態(tài)下的添加的,并包裹懶加載組件。 引言 antd的Tooltip組件在react-componment/trigger的基礎(chǔ)上進(jìn)行封裝,而組件Popover和Popconfirm是使用Tooltip組件的進(jìn)行pop,在react-com...
摘要:在裝載組件之前調(diào)用會(huì)組件的構(gòu)造函數(shù)。當(dāng)實(shí)現(xiàn)子類的構(gòu)造函數(shù)時(shí),應(yīng)該在任何其他語(yǔ)句之前調(diào)用設(shè)置初始狀態(tài)綁定鍵盤回車事件,添加新任務(wù)修改狀態(tài)值,每次修改以后,自動(dòng)調(diào)用方法,再次渲染組件??梢酝ㄟ^(guò)直接安裝到項(xiàng)目中,使用或進(jìn)行引用。 首先我們看一下我們完成后的最終形態(tài):TodoMvc: showImg(https://segmentfault.com/img/remote/14600000085...
摘要:這個(gè)組件是一個(gè)圖釘組件,使用的布局,讓組件固定在窗口的某一個(gè)位置上,并且可以在到達(dá)指定位置的時(shí)候才去固定。 Affix 這個(gè)組件是一個(gè)圖釘組件,使用的fixed布局,讓組件固定在窗口的某一個(gè)位置上,并且可以在到達(dá)指定位置的時(shí)候才去固定。 AffixProps 還是老樣子,看一個(gè)組件首先我們先來(lái)看看他可以傳入什么參數(shù) // Affix export interface Affix...
閱讀 333·2025-02-07 13:40
閱讀 503·2025-02-07 13:37
閱讀 786·2024-11-06 13:38
閱讀 972·2024-09-10 13:19
閱讀 1166·2024-08-22 19:45
閱讀 1439·2021-11-19 09:40
閱讀 2719·2021-11-18 13:14
閱讀 4351·2021-10-09 10:02