摘要:這個組件是一個圖釘組件,使用的布局,讓組件固定在窗口的某一個位置上,并且可以在到達指定位置的時候才去固定。
Affix
這個組件是一個圖釘組件,使用的fixed布局,讓組件固定在窗口的某一個位置上,并且可以在到達指定位置的時候才去固定。
AffixProps還是老樣子,看一個組件首先我們先來看看他可以傳入什么參數(shù)
// Affix export interface AffixProps { /** * 距離窗口頂部達到指定偏移量后觸發(fā) */ offsetTop?: number; offset?: number; /** 距離窗口底部達到指定偏移量后觸發(fā) */ offsetBottom?: number; style?: React.CSSProperties; /** 固定狀態(tài)改變時觸發(fā)的回調(diào)函數(shù) */ onChange?: (affixed?: boolean) => void; /** 設置 Affix 需要監(jiān)聽其滾動事件的元素,值為一個返回對應 DOM 元素的函數(shù) */ target?: () => Window | HTMLElement; // class樣式命名空間,可以定義自己的樣式命名 prefixCls?: string; }Render()
看完傳入?yún)?shù)之后,就到入口函數(shù)看看這里用到了什么參數(shù)
render() { // 構造當前組件的class樣式 const className = classNames({ [this.props.prefixCls || "ant-affix"]: this.state.affixStyle, }); // 這里和之前看的一樣,忽略掉props中的在div標簽上面不需要的一些屬性 // 但是貌似沒有去掉offset,后面我還查了一下DIV上面能不能有offset // 但是沒看見有offset,只看見offsetLeft, offsetHeight.... const props = omit(this.props, ["prefixCls", "offsetTop", "offsetBottom", "target", "onChange"]); const placeholderStyle = { ...this.state.placeholderStyle, ...this.props.style }; return ( // 注意咯 看這里placeholder的作用了 如圖 // 這里的placeholder的作用是當這個組件樣式變?yōu)閒ixed的時候, // 會脫離文檔流,然后導致原本的dom結構變化,寬高都會有所變化 // 所以這是后放一個占位元素來頂住這一組件脫離文檔流的時候的影響完整代碼); }{this.props.children}
import React from "react"; import ReactDOM from "react-dom"; import PropTypes from "prop-types"; import addEventListener from "rc-util/lib/Dom/addEventListener"; import classNames from "classnames"; import shallowequal from "shallowequal"; import omit from "omit.js"; import getScroll from "../_util/getScroll"; import { throttleByAnimationFrameDecorator } from "../_util/throttleByAnimationFrame"; function getTargetRect(target): ClientRect { return target !== window ? target.getBoundingClientRect() : { top: 0, left: 0, bottom: 0 }; } function getOffset(element: HTMLElement, target) { const elemRect = element.getBoundingClientRect(); const targetRect = getTargetRect(target); const scrollTop = getScroll(target, true); const scrollLeft = getScroll(target, false); const docElem = window.document.body; const clientTop = docElem.clientTop || 0; const clientLeft = docElem.clientLeft || 0; return { top: elemRect.top - targetRect.top + scrollTop - clientTop, left: elemRect.left - targetRect.left + scrollLeft - clientLeft, width: elemRect.width, height: elemRect.height, }; } function noop() {} function getDefaultTarget() { return typeof window !== "undefined" ? window : null; } // Affix export interface AffixProps { /** * 距離窗口頂部達到指定偏移量后觸發(fā) */ offsetTop?: number; offset?: number; /** 距離窗口底部達到指定偏移量后觸發(fā) */ offsetBottom?: number; style?: React.CSSProperties; /** 固定狀態(tài)改變時觸發(fā)的回調(diào)函數(shù) */ onChange?: (affixed?: boolean) => void; /** 設置 Affix 需要監(jiān)聽其滾動事件的元素,值為一個返回對應 DOM 元素的函數(shù) */ target?: () => Window | HTMLElement; prefixCls?: string; } export default class Affix extends React.Component{ static propTypes = { offsetTop: PropTypes.number, offsetBottom: PropTypes.number, target: PropTypes.func, }; scrollEvent: any; resizeEvent: any; timeout: any; refs: { fixedNode: HTMLElement; }; events = [ "resize", "scroll", "touchstart", "touchmove", "touchend", "pageshow", "load", ]; eventHandlers = {}; constructor(props) { super(props); this.state = { affixStyle: null, placeholderStyle: null, }; } setAffixStyle(e, affixStyle) { const { onChange = noop, target = getDefaultTarget } = this.props; const originalAffixStyle = this.state.affixStyle; const isWindow = target() === window; if (e.type === "scroll" && originalAffixStyle && affixStyle && isWindow) { return; } if (shallowequal(affixStyle, originalAffixStyle)) { return; } this.setState({ affixStyle }, () => { const affixed = !!this.state.affixStyle; if ((affixStyle && !originalAffixStyle) || (!affixStyle && originalAffixStyle)) { onChange(affixed); } }); } setPlaceholderStyle(placeholderStyle) { const originalPlaceholderStyle = this.state.placeholderStyle; if (shallowequal(placeholderStyle, originalPlaceholderStyle)) { return; } this.setState({ placeholderStyle }); } @throttleByAnimationFrameDecorator() updatePosition(e) { let { offsetTop, offsetBottom, offset, target = getDefaultTarget } = this.props; const targetNode = target(); // Backwards support offsetTop = offsetTop || offset; const scrollTop = getScroll(targetNode, true); const affixNode = ReactDOM.findDOMNode(this) as HTMLElement; const elemOffset = getOffset(affixNode, targetNode); const elemSize = { width: this.refs.fixedNode.offsetWidth, height: this.refs.fixedNode.offsetHeight, }; const offsetMode = { top: false, bottom: false, }; // Default to `offsetTop=0`. if (typeof offsetTop !== "number" && typeof offsetBottom !== "number") { offsetMode.top = true; offsetTop = 0; } else { offsetMode.top = typeof offsetTop === "number"; offsetMode.bottom = typeof offsetBottom === "number"; } const targetRect = getTargetRect(targetNode); const targetInnerHeight = (targetNode as Window).innerHeight || (targetNode as HTMLElement).clientHeight; if (scrollTop > elemOffset.top - (offsetTop as number) && offsetMode.top) { // Fixed Top const width = elemOffset.width; this.setAffixStyle(e, { position: "fixed", top: targetRect.top + (offsetTop as number), left: targetRect.left + elemOffset.left, width, }); this.setPlaceholderStyle({ width, height: elemSize.height, }); } else if ( scrollTop < elemOffset.top + elemSize.height + (offsetBottom as number) - targetInnerHeight && offsetMode.bottom ) { // Fixed Bottom const targetBottomOffet = targetNode === window ? 0 : (window.innerHeight - targetRect.bottom); const width = elemOffset.width; this.setAffixStyle(e, { position: "fixed", bottom: targetBottomOffet + (offsetBottom as number), left: targetRect.left + elemOffset.left, width, }); this.setPlaceholderStyle({ width, height: elemOffset.height, }); } else { const { affixStyle } = this.state; if (e.type === "resize" && affixStyle && affixStyle.position === "fixed" && affixNode.offsetWidth) { this.setAffixStyle(e, { ...affixStyle, width: affixNode.offsetWidth }); } else { this.setAffixStyle(e, null); } this.setPlaceholderStyle(null); } } componentDidMount() { const target = this.props.target || getDefaultTarget; // Wait for parent component ref has its value this.timeout = setTimeout(() => { this.setTargetEventListeners(target); }); } componentWillReceiveProps(nextProps) { if (this.props.target !== nextProps.target) { this.clearEventListeners(); this.setTargetEventListeners(nextProps.target); // Mock Event object. this.updatePosition({}); } } componentWillUnmount() { this.clearEventListeners(); clearTimeout(this.timeout); (this.updatePosition as any).cancel(); } setTargetEventListeners(getTarget) { const target = getTarget(); if (!target) { return; } this.clearEventListeners(); this.events.forEach(eventName => { this.eventHandlers[eventName] = addEventListener(target, eventName, this.updatePosition); }); } clearEventListeners() { this.events.forEach(eventName => { const handler = this.eventHandlers[eventName]; if (handler && handler.remove) { handler.remove(); } }); } render() { const className = classNames({ [this.props.prefixCls || "ant-affix"]: this.state.affixStyle, }); const props = omit(this.props, ["prefixCls", "offsetTop", "offsetBottom", "target", "onChange"]); const placeholderStyle = { ...this.state.placeholderStyle, ...this.props.style }; return ( ); } }{this.props.children}
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/89188.html
摘要:作為開發(fā)當中使用相對頻繁的一個組件,其實現(xiàn)也很簡單,但是其中比較麻煩的一部分是字體的制作,可以參看這篇文章。接口中的種屬性方法,不屬于上述六種。為事件屬性,可以大家也可以根據(jù)上面所提供的制作的方法和這樣的方式來實現(xiàn)自己的組件 Icon icon作為開發(fā)當中使用相對頻繁的一個組件,其實現(xiàn)也很簡單,但是其中比較麻煩的一部分是icon字體的制作,可以參看這篇文章。 Antd的Icon組件使用...
github: 地址gitbook: 地址 Index.js 看一個代碼的時候首先當然是從他的入口文件開始看起,所以第一份代碼我們看的是/index.js文件 開始 打開index.js文件,代碼只有28行,其中包含了一個camelCase函數(shù)(看函數(shù)名就知道這是個給名稱進行駝峰命名法的函數(shù)),一個req變量,以及這個的變量操作和export操作 在這個文件里面我首先查了require.conte...
摘要:結構項目結構如下,負責外層封裝,負責事件綁定與渲染控制。節(jié)點通過決定事件綁定情況,即通過屬性綁定事件情況,事件控制組件的屬性,這里就不詳細說了。為隱藏狀態(tài)下的添加的,并包裹懶加載組件。 引言 antd的Tooltip組件在react-componment/trigger的基礎上進行封裝,而組件Popover和Popconfirm是使用Tooltip組件的進行pop,在react-com...
摘要:引言看過源碼的都知道,其實是在一組組件的基礎上進行了一層封裝,本文主要解讀組件的基礎組件,另外會略過模式下的代碼。解讀源碼首先要從自己最常用的或者感興趣的入手,首先組件最主要的還是在這個裝飾器入手。 引言 看過antd源碼的都知道,antd其實是在一組react-componment組件的基礎上進行了一層ui封裝,本文主要解讀antd組件Form的基礎組件react-componmen...
Button Button包括了兩個組件,Button與ButtonGroup。 ButtonProps 看一個組件首先看的是他的傳參也就是props,所以我們這里先看Button組件的ButtonProps export type ButtonType = primary | ghost | dashed | danger; export type ButtonShape = circl...
閱讀 2715·2021-11-22 13:52
閱讀 1184·2021-10-14 09:43
閱讀 3640·2019-08-30 15:56
閱讀 2952·2019-08-30 13:22
閱讀 3269·2019-08-30 13:10
閱讀 1563·2019-08-26 13:45
閱讀 1102·2019-08-26 11:47
閱讀 2789·2019-08-23 18:13