react中获取dom节点和全局上下文
同vue一样,说是尽量不操作dom,数据驱动视图,实际上免不了需要dom的时候React.createRef(); 通过该api在构造器中创建一个用于绑定dom节点的变量用于绑定dom节点的变量 通过.current来获取真实domthis.textInput.current.focus();class CustomTextInput extends React.Component {constr
·
同vue一样,说是尽量不操作dom,数据驱动视图,实际上免不了需要dom的时候
在类组件中操作dom
React.createRef(); 通过该api在构造器中创建一个用于绑定dom节点的变量
用于绑定dom节点的变量 通过 .current 来获取真实dom
this.textInput.current.focus();
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// 创造一个 textInput DOM 元素的 ref
this.textInput = React.createRef();
}
render() {
// 使用 `ref` 回调函数以在实例的一个变量中存储文本输入 DOM 元素
//(比如,this.textInput)。
return (
<input
type="text"
ref={this.textInput}
/>
);
}
}
当父级需要获取子组件的真实dom时
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.inputElement = React.createRef();
}
render() {
return (
<CustomTextInput inputRef={this.inputElement} />
);
}
}
// 现在你就可以在需要时设置焦点了
this.inputElement.current.focus();
在函数组件中操作dom
函数组件有专门的hooks,useRef来获取dom节点
demo如下:
//在class中通过 React.createRef() 来绑定和操作dom hooks中有不同的api
import React, { useRef } from "react";
function Example() {
const divRef = useRef();
function changeDOM() {
// 获取整个div
console.log("整个div", divRef.current);
// 获取div的class
console.log("div的class", divRef.current.className);
// 获取div自定义属性
console.log("div自定义属性", divRef.current.getAttribute("data-clj"));
}
return (
<div>
<div className="div-class" data-clj="我是div的自定义属性" ref={divRef}>
我是div
</div>
<button onClick={(e) => changeDOM()}>获取DOM</button>
</div>
);
}
export default Example;
一个dialog的案例
点击按钮弹框显示,点击弹框之外的部分弹框消失。
if (this.state.isOpen && !this.toggleContainer.current.contains(event.target)) {
this.setState({ isOpen: false });
}//关闭的判断条件 当前弹框打开,点击区域不包含弹框
class OuterClickExample extends React.Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
this.toggleContainer = React.createRef();
this.onClickHandler = this.onClickHandler.bind(this);
this.onClickOutsideHandler = this.onClickOutsideHandler.bind(this);
}
componentDidMount() {
window.addEventListener('click', this.onClickOutsideHandler);
}
componentWillUnmount() {
window.removeEventListener('click', this.onClickOutsideHandler);
}
onClickHandler() {
this.setState(currentState => ({
isOpen: !currentState.isOpen
}));
}
onClickOutsideHandler(event) {
if (this.state.isOpen && !this.toggleContainer.current.contains(event.target)) {
this.setState({ isOpen: false });
}
}
render() {
return (
<div ref={this.toggleContainer}>
<button onClick={this.onClickHandler}>Select an option</button>
{this.state.isOpen && (
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
)}
</div>
);
}
}
考虑到键盘用户的弹出层
class BlurExample extends React.Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
this.timeOutId = null;
this.onClickHandler = this.onClickHandler.bind(this);
this.onBlurHandler = this.onBlurHandler.bind(this);
this.onFocusHandler = this.onFocusHandler.bind(this);
}
onClickHandler() {
this.setState(currentState => ({
isOpen: !currentState.isOpen
}));
}
// 我们在下一个时间点使用 setTimeout 关闭弹窗。
// 这是必要的,因为失去焦点事件会在新的焦点事件前被触发,
// 我们需要通过这个步骤确认这个元素的一个子节点
// 是否得到了焦点。
onBlurHandler() {
this.timeOutId = setTimeout(() => {
this.setState({
isOpen: false
});
});
}
// 如果一个子节点获得了焦点,不要关闭弹窗。
onFocusHandler() {
clearTimeout(this.timeOutId);
}
render() {
// React 通过把失去焦点和获得焦点事件传输给父节点
// 来帮助我们。
return (
<div onBlur={this.onBlurHandler}
onFocus={this.onFocusHandler}>
<button onClick={this.onClickHandler}
aria-haspopup="true"
aria-expanded={this.state.isOpen}>
Select an option
</button>
{this.state.isOpen && (
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
)}
</div>
);
}
}
context
theme-context.js 主题文件
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext(
themes.dark // 默认值
);
themed-button.js button组件
import {ThemeContext} from './theme-context';
class ThemedButton extends React.Component {
render() {
let props = this.props;
let theme = this.context;
return (
<button
{...props}
style={{backgroundColor: theme.background}}
/>
);
}
}
ThemedButton.contextType = ThemeContext; //实现全局上下文与本组件的绑定
export default ThemedButton;
app.js
通过.Provider来建立全局状态 ,之后在其引用的任意层级的组件内通过 .Consumer来获取状态
import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';
// 一个使用 ThemedButton 的中间组件
function Toolbar(props) {
return (
<ThemedButton onClick={props.changeTheme}>
Change Theme
</ThemedButton>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
}
render() {
// 在 ThemeProvider 内部的 ThemedButton 按钮组件使用 state 中的 theme 值,
// 而外部的组件使用默认的 theme 值
return (
<Page>
<ThemeContext.Provider value={this.state.theme}>
<Toolbar changeTheme={this.toggleTheme} />
</ThemeContext.Provider>
<Section>
<ThemedButton />
</Section>
</Page>
);
}
}
const root = ReactDOM.createRoot(
document.getElementById('root')
);
root.render(<App />);
下面代码为如何在函数组件中获取全局对象...
import { UserContext, TokenContext } from "./index";
//通过useContext 可以获取顶层的状态
function Example() {
let user = useContext(UserContext);
let token = useContext(TokenContext);
console.log("UserContext", user);
console.log("TokenContext", token);
return (
<div>
name:{user?.name},age:{user?.age}
</div>
);
更多推荐
已为社区贡献1条内容
所有评论(0)