react学习笔记3——基于React脚手架
React路由
相关理解
SPA的理解
- 单页Web应用(single page web application,SPA)。
- 整个应用只有一个完整的页面。
- 点击页面中的链接不会刷新页面,只会做页面的局部更新。
- 数据都需要通过ajax请求获取, 并在前端异步展现。
路由的理解
- 什么是路由?
- 一个路由就是一个映射关系(key:value)
- key为路径, value可能是function或component
- 路由分类
- 后端路由:
- 理解: value是function, 用来处理客户端提交的请求。
- 注册路由: router.get(path, function(req, res))
- 工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
- 前端路由:
- 浏览器端路由,value是component,用于展示页面内容。
- 注册路由: <Route path="/test" component={Test}>
- 工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件
- 后端路由:
react-router-dom的理解
- react的一个插件库。
- 专门用来实现一个SPA应用。
- 基于react的项目基本都会用到此库。
react-router-dom相关API
内置组件
- <BrowserRouter>
- <HashRouter>
- <Route>
- <Redirect>
- <Link>
- <NavLink>
- <Switch>
其它
- history对象
- match对象
- withRouter函数
基本路由使用
准备
- 下载react-router-dom: npm install --save react-router-dom
- 引入bootstrap.css: <link rel="stylesheet" href="/css/bootstrap.css">
路由的基本使用
index.js
//引入react核心库
import React from "react";
//引入ReactDOM
import ReactDOM from "react-dom/client";
//
import { BrowserRouter, HashRouter } from "react-router-dom";
//引入App
import App from "./App";const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<HashRouter><App /></HashRouter>
);
App.jsx
import React, { Component } from "react";
import { Link, Route } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><div className="page-header"><h2>React Router Demo</h2></div></div></div>{/* <BrowserRouter> */}<div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group">{/* 原生html中,靠<a>跳转到不同的页面 */}{/* <a className="list-group-item" href="./about.html">About</a><a className="list-group-item active" href="./home.html">Home</a> */}{/* 在React中靠路由链接实现切换组件 */}<Link className="list-group-item" to="/about">About</Link><Link className="list-group-item" to="/home">Home</Link></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body">{/* 注册路由 */}<Route path="/about" component={About} /><Route path="/home" component={Home} /></div></div></div></div>{/* </BrowserRouter> */}</div>);}
}
About/index.jsx
import React, { Component } from 'react'export default class index extends Component {render() {return (<h3>我是About的内容</h3>)}
}
Home/index.jsx
import React, { Component } from 'react'export default class index extends Component {render() {return (<h3>我是Home的内容</h3>)}
}
NavLink的使用
index.js
//引入react核心库
import React from "react";
//引入ReactDOM
import ReactDOM from "react-dom/client";
//
import { BrowserRouter, HashRouter } from "react-router-dom";
//引入App
import App from "./App";const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<BrowserRouter><App /></BrowserRouter>
);
App.jsx
import React, { Component } from "react";
import { NavLink, Route } from "react-router-dom";
import Home from "./pages/Home"; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header/></div></div>{/* <BrowserRouter> */}<div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group">{/* 原生html中,靠<a>跳转到不同的页面 */}{/* <a className="list-group-item" href="./about.html">About</a><a className="list-group-item active" href="./home.html">Home</a> */}{/* 在React中靠路由链接实现切换组件 */}<NavLink activeClassName="atguigu" className="list-group-item" to="/about">About</NavLink><NavLink activeClassName="atguigu" className="list-group-item" to="/home">Home</NavLink></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body">{/* 注册路由 */}<Route path="/about" component={About} /><Route path="/home" component={Home} /></div></div></div></div>{/* </BrowserRouter> */}</div>);}
}
About/index.jsx
import React, { Component } from 'react'export default class index extends Component {render() {// console.log('About组件收到的props是',this.props);return (<h3>我是About的内容</h3>)}
}
Home/index.jsx
import React, { Component } from 'react'export default class index extends Component {render() {return (<h3>我是Home的内容</h3>)}
}
封装NavLink
同上部分文件index.js,about,home
App.jsx
import React, { Component } from "react";
import { Route } from "react-router-dom";
import Home from "./pages/Home"; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/Header/MyNavLink";
export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header/></div></div>{/* <BrowserRouter> */}<div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group">{/* 原生html中,靠<a>跳转到不同的页面 */}{/* <a className="list-group-item" href="./about.html">About</a><a className="list-group-item active" href="./home.html">Home</a> */}{/* 在React中靠路由链接实现切换组件————编写路由链接 */}{/* <MyNavLink to="/about" title="About" a={1} b={2} c={3} /><MyNavLink to="/home" title="Home"/> */}{/* 把标签名作为标签体放在标签里面 */}{/* 标签属性,标签体内容 */}{/* <MyNavLink to="/about" a={1} b={2} c={3}>About</MyNavLink><MyNavLink to="/home">Home</MyNavLink> */}{/* 可以把标签体的内容配在children属性中,也就不需要写开始标签与结束标签,直接自闭合就可以了 */}{/* <NavLink to="/about" children="About"/> */}<MyNavLink to="/about">About</MyNavLink><MyNavLink to="home">Home</MyNavLink></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body">{/* 注册路由 */}<Route path="/about" component={About} /><Route path="/home" component={Home} /></div></div></div></div>{/* </BrowserRouter> */}</div>);}
}
components/MyNavLin/index.jsx
import React, { Component } from "react";
import { NavLink } from "react-router-dom";
export default class MyNavLink extends Component {render() {// props也可以拿到标签体内容console.log(this.props);// const {to,title} = this.propsreturn (// {...this.props} 这样写将封装的NavLink标签里面的所有属性都带过来了,包括原本可以写在标签体中的children属性<NavLink activeClassName="atguigu" className="list-group-item" {...this.props} />);}
}
components/Header/index.jsx
import React, { Component } from 'react'export default class Header extends Component {render() {// console.log('Header组件收到的props是',this.props);return (<div className="page-header"><h2>React Router Demo</h2></div>)}
}
Switch的使用
App.jsx
import React, { Component } from "react";
import { Route,Switch } from "react-router-dom";
import Home from "./pages/Home"; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/Header/MyNavLink";
import Test from './pages/Test'
export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header/></div></div>{/* <BrowserRouter> */}<div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group">{/* 原生html中,靠<a>跳转到不同的页面 */}{/* <a className="list-group-item" href="./about.html">About</a><a className="list-group-item active" href="./home.html">Home</a> */}{/* 在React中靠路由链接实现切换组件————编写路由链接 */}{/* <MyNavLink to="/about" title="About" a={1} b={2} c={3} /><MyNavLink to="/home" title="Home"/> */}{/* 把标签名作为标签体放在标签里面 */}{/* 标签属性,标签体内容 */}{/* <MyNavLink to="/about" a={1} b={2} c={3}>About</MyNavLink><MyNavLink to="/home">Home</MyNavLink> */}{/* 可以把标签体的内容配在children属性中,也就不需要写开始标签与结束标签,直接自闭合就可以了 */}{/* <NavLink to="/about" children="About"/> */}<MyNavLink to="/about">About</MyNavLink><MyNavLink to="home">Home</MyNavLink></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body">{/* 注册路由 */}{/* 正常情况下 ,应该是path匹配上一个组件之后就不在继续往下匹配了,而目前的情况是path匹配上一个组件之后还会继续往下匹配,将所有匹配上的内容都展示在同一个path中 */}{/* 最好是让path匹配上一个之后就不继续往下问了,否则的话,继续往下面匹配,当组件特别多的时候,效率就会特别低 */}{/* 提高效率的方式,使用Switch,匹配上一个就不继续往下匹配了,可以改变顺序测试一下,谁在上面就先显示谁 */}<Switch><Route path="/about" component={About} /><Route path="/home" component={Home} /><Route path="/home" component={Test} /></Switch></div></div></div></div>{/* </BrowserRouter> */}</div>);}
}
pages/Test/index.jsx
import React, { Component } from 'react'export default class Test extends Component {render() {return (<div><h2>Test...</h2></div>)}
}
解决样式丢失问题
index.js
//引入react核心库
import React from "react";
//引入ReactDOM
import ReactDOM from "react-dom/client";
//
import { BrowserRouter, HashRouter } from "react-router-dom";
//引入App
import App from "./App";// 解决样式丢失问题三
//改变路由模式 #后面都是hash值,向3000请求数据的时候就不会带#后面的东西
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<BrowserRouter><App /></BrowserRouter>
);
App.jsx
import React, { Component } from "react";
import { Route,Switch } from "react-router-dom";
import Home from "./pages/Home"; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/MyNavLink";
export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header/></div></div>{/* <BrowserRouter> */}<div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group">{/* 原生html中,靠<a>跳转到不同的页面 */}{/* <a className="list-group-item" href="./about.html">About</a><a className="list-group-item active" href="./home.html">Home</a> */}{/* 在React中靠路由链接实现切换组件————编写路由链接 */}{/* <MyNavLink to="/about" title="About" a={1} b={2} c={3} /><MyNavLink to="/home" title="Home"/> */}{/* 把标签名作为标签体放在标签里面 */}{/* 标签属性,标签体内容 */}{/* <MyNavLink to="/about" a={1} b={2} c={3}>About</MyNavLink><MyNavLink to="/home">Home</MyNavLink> */}{/* 可以把标签体的内容配在children属性中,也就不需要写开始标签与结束标签,直接自闭合就可以了 */}{/* <NavLink to="/about" children="About"/> */}<MyNavLink to="/atguigu/about">About</MyNavLink><MyNavLink to="/atguigu/home">Home</MyNavLink></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body">{/* 注册路由 */}<Switch><Route path="/atguigu/about" component={About} /><Route path="/atguigu/home" component={Home} /></Switch></div></div></div></div>{/* </BrowserRouter> */}</div>);}
}
public/index.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="icon" href="%PUBLIC_URL%/favicon.ico" /><!-- ./以当前文件出发,去当前文件去找,这样写的话,在多级路径的情况下,就会把atguigu也带上了,在访问的时候 --><!-- <link rel="stylesheet" href="./css/bootstrap.css" /> --><!-- /表示的是直接去localhost:3000下面去请求东西,3000/css/bootstrap --><!-- 解决样式丢失问题一 --><!-- <link rel="stylesheet" href="/css/bootstrap.css" /> --><!-- %PUBLIC_URL%代表的是public这个下面的绝对路径 --><!-- 解决样式丢失问题二 --><link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css" /><style>/* 刚开始点击路由组件高亮的显示并不正常,原因是bootstrap的权限比较高,需要需要加上!important增加权限 */.atguigu {background-color: orange !important;color: white !important;}</style></head><body><div id="root"></div></body>
</html>
精准匹配与模糊匹配
App.jsx
import React, { Component } from "react";
import { Route,Switch } from "react-router-dom";
import Home from "./pages/Home"; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/Header/MyNavLink";
export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header/></div></div>{/* <BrowserRouter> */}<div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group">{/* 原生html中,靠<a>跳转到不同的页面 */}{/* <a className="list-group-item" href="./about.html">About</a><a className="list-group-item active" href="./home.html">Home</a> */}{/* 在React中靠路由链接实现切换组件————编写路由链接 */}{/* <MyNavLink to="/about" title="About" a={1} b={2} c={3} /><MyNavLink to="/home" title="Home"/> */}{/* 把标签名作为标签体放在标签里面 */}{/* 标签属性,标签体内容 */}{/* <MyNavLink to="/about" a={1} b={2} c={3}>About</MyNavLink><MyNavLink to="/home">Home</MyNavLink> */}{/* 可以把标签体的内容配在children属性中,也就不需要写开始标签与结束标签,直接自闭合就可以了 */}{/* <NavLink to="/about" children="About"/> */}<MyNavLink to="/about">About</MyNavLink>{/* 给多了,但是没要那么多,就是模糊匹配 */}{/* <MyNavLink to="/home/a/b">Home</MyNavLink> */}{/* 精准匹配,多给少给都匹配不上 */}<MyNavLink to="/home">Home</MyNavLink>{/* 这样匹配不上 */}{/* <MyNavLink to="/a/home/b">Home</MyNavLink> */}</div></div><div className="col-xs-6"><div className="panel"><div className="panel-body">{/* 注册路由 */}<Switch>{/* 精准匹配,多给少给都匹配不上,exact默认true */}<Route exact={true} path="/about" component={About} /><Route exact path="/home" component={Home} />{/* 不匹配 */}{/* 给少了,匹配的地方更多,就会匹配不上 */}{/* <Route path="/home/a/b" component={Home} /> */}</Switch></div></div></div></div>{/* </BrowserRouter> */}</div>);}
}
Redirect的使用
刚进网页页面的时候什么都没有选中
App.jsx
import React, { Component } from "react";
import { Route, Switch,Redirect } from "react-router-dom";
import Home from "./pages/Home"; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/Header/MyNavLink";
export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header /></div></div>{/* <BrowserRouter> */}<div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group">{/* 在React中靠路由链接实现切换组件————编写路由链接 */}<MyNavLink to="/about">About</MyNavLink><MyNavLink to="/home">Home</MyNavLink></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body">{/* 注册路由 */}<Switch><Route path="/about" component={About} /><Route path="/home" component={Home} />{/* 一般放在所有路由注册的最下方,当所有路由都无法匹配的时,跳转到Redirect指定的路由 */}<Redirect to="/about" /></Switch></div></div></div></div>{/* </BrowserRouter> */}</div>);}
}
嵌套路由使用
嵌套路由的使用
App.jsx
import React, { Component } from "react";
import { Route, Switch,Redirect } from "react-router-dom";
import Home from "./pages/Home"; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/MyNavLink";
export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header /></div></div>{/* <BrowserRouter> */}<div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group">{/* 在React中靠路由链接实现切换组件————编写路由链接 */}<MyNavLink to="/about">About</MyNavLink><MyNavLink to="/home">Home</MyNavLink></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body">{/* 注册路由 */}<Switch><Route path="/about" component={About} /><Route path="/home" component={Home} />{/* 会导致无法开启二级路由 */}<Route exact path="/home" component={Home} />{/* 一般放在所有路由注册的最下方,当所有路由都无法匹配的时,跳转到Redirect指定的路由 */}<Redirect to="/about" /></Switch></div></div></div></div>{/* </BrowserRouter> */}</div>);}
}
pages/Home/index.jsx
import React, { Component } from 'react'
//默认暴露,这样引入
import MyNavLink from '../../components/MyNavLink'
import { Route,Switch,Redirect } from 'react-router-dom'
import News from './News'
import Message from './Message'
export default class index extends Component {render() {return (<div><h3>我是Home的内容</h3><div><ul className="nav nav-tabs"><li>{/* 由于模糊匹配,可以匹配成功 */}<MyNavLink to="/home/news">News</MyNavLink></li><li><MyNavLink to="/home/message">Message</MyNavLink></li></ul>{/* 注册路由 */}{/* 如果路径是/home/news下的,就匹配News */}<Switch><Route path="/home/news" component={News} /><Route path="/home/message" component={Message} />{/* 会导致无法开启二级路由 */}{/* <Route exact path="/home/message" component={Message} /> */}<Redirect to="/home/news" /></Switch></div></div>)}
}
pages/Home/Message/index.jsx
import React, { Component } from "react";export default class Message extends Component {render() {return (<div><ul><li><a href="/message1">message001</a> </li><li><a href="/message2">message002</a> </li><li><a href="/message/3">message003</a> </li></ul></div>);}
}
pages/Home/News/index.jsx
import React, { Component } from 'react'export default class News extends Component {render() {return (<ul><li>news001</li><li>news002</li><li>news003</li></ul>)}
}
多种路由跳转方式
向路由组件传递params参数
pages/Home/index.jsx
import React, { Component } from 'react'
//默认暴露,这样引入
import MyNavLink from '../../components/MyNavLink'
import { Route,Switch,Redirect } from 'react-router-dom'
import News from './News'
import Message from './Message'
export default class index extends Component {render() {return (<div><h3>我是Home的内容</h3><div><ul className="nav nav-tabs"><li>{/* 由于模糊匹配,可以匹配成功 */}<MyNavLink to="/home/news">News</MyNavLink></li><li><MyNavLink to="/home/message">Message</MyNavLink></li></ul>{/* 注册路由 */}{/* 如果路径是/home/news下的,就匹配News */}<Switch><Route path="/home/news" component={News} /><Route path="/home/message" component={Message} />{/* 会导致无法开启二级路由 */}{/* <Route exact path="/home/message" component={Message} /> */}<Redirect to="/home/news" /></Switch></div></div>)}
}
pages/Home/Message/index.jsx
import React, { Component } from "react";
import {Link,Route} from 'react-router-dom'
import Detail from './Detail'
export default class Message extends Component {state = {messageArr: [{ id: '01', title: '消息1' },{ id: '02', title: '消息2' },{ id: '03', title: '消息3' }]}render() {const { messageArr } = this.statereturn (<div><ul>{messageArr.map((msgObj) => {return (<li key={msgObj.id}>{/* 模板字符串是js里面的东西,所以要使用{``},模板字符串里面要混入,就写{} */}{/* 这样写相当于模糊匹配,上面多,下面少,下面没有接收到 */}{/* 向路由组件传递params参数 */}<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> </li>)})}</ul><hr />{/* 声明接受params参数,前面是path值,后面是传递的id */}<Route path="/home/message/detail/:id/:title" component={Detail} /></div>);}
}
pages/Home/Message/Detail/index.jsx
import React, { Component } from 'react'
// 在子组件接收需要暂时的参数
const DetailData = [{id:'01',content: '你好,中国'},{id:'02',content: '你好,尚硅谷'},{id:'03',content: '你好,未来的自己'},
]
export default class Detail extends Component {render() {const {id,title} = this.props.match.paramsconst findResult = DetailData.find((detailObj)=>{return detailObj.id === id})return (<ul><li>ID: {id}</li><li>TITLE: {title}</li><li>CONTENT: {findResult.content}</li></ul>)}
}
向路由组件传递search参数
pages/Home/Message/index.jsx
import React, { Component } from "react";
import {Link,Route} from 'react-router-dom'
import Detail from './Detail'
export default class Message extends Component {state = {messageArr: [{ id: '01', title: '消息1' },{ id: '02', title: '消息2' },{ id: '03', title: '消息3' }]}render() {const { messageArr } = this.statereturn (<div><ul>{messageArr.map((msgObj) => {return (<li key={msgObj.id}>{/* 模板字符串是js里面的东西,所以要使用{``},模板字符串里面要混入,就写{} */}{/* 这样写相当于模糊匹配,上面多,下面少,下面没有接收到 */}{/* 向路由组件传递params参数 */}{/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}{/* 向路由组件传递search参数 */}<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> </li>)})}</ul><hr />{/* 声明接受params参数,前面是path值,后面是传递的id */}{/* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}{/* search参数无需声明接收、正常注册路由即可 */}<Route path="/home/message/detail" component={Detail} /></div>);}
}
pages/Home/Message/Detail/index.jsx
import React, { Component } from 'react'
import qs from 'querystring'
// let obj ={name:'tom',age:18} //name=tom&age=18 key=value&key=value urlencoded的编码
// console.log(qs.stringify(obj)) //name=tom&age=18
// let str = 'carName=奔驰&price=199'
// console.log(qs.parse(str)); //{carName: '奔驰', price: '199'}
// 在子组件接收需要暂时的参数
const DetailData = [{id:'01',content: '你好,中国'},{id:'02',content: '你好,尚硅谷'},{id:'03',content: '你好,未来的自己'},
]
export default class Detail extends Component {render() {console.log(this.props);//接受params参数// const {id,title} = this.props.match.params// 接收search参数const {search} = this.props.locationconst {id,title} = qs.parse(search.slice(1))const findResult = DetailData.find((detailObj)=>{return detailObj.id === id})return (<ul><li>ID: {id}</li><li>TITLE: {title}</li><li>CONTENT: {findResult.content}</li></ul>)}
}
向路由组件传递state参数
pages/Home/Message/index.jsx
import React, { Component } from "react";
import {Link,Route} from 'react-router-dom'
import Detail from './Detail'
export default class Message extends Component {state = {messageArr: [{ id: '01', title: '消息1' },{ id: '02', title: '消息2' },{ id: '03', title: '消息3' }]}render() {const { messageArr } = this.statereturn (<div><ul>{messageArr.map((msgObj) => {return (<li key={msgObj.id}>{/* 传递数据刷新数据不会丢失 */}{/* 模板字符串是js里面的东西,所以要使用{``},模板字符串里面要混入,就写{} */}{/* 这样写相当于模糊匹配,上面多,下面少,下面没有接收到 */}{/* 向路由组件传递params参数 */}{/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}{/* 向路由组件传递search参数 */}{/* <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */}{/* 向路由组件传递state参数 */}{/* 这种方式传递数据刷新数据不会丢失 */}<Link replace to={{pathname: '/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link> </li>)})}</ul><hr />{/* 声明接受params参数,前面是path值,后面是传递的id */}{/* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}{/* search参数无需声明接收、正常注册路由即可 */}{/* <Route path="/home/message/detail" component={Detail} /> */}{/* state参数无需声明接收、正常注册路由即可 */}<Route path="/home/message/detail" component={Detail} /></div>);}
}
pages/Home/Message/Detail/index.jsx
import React, { Component } from 'react'
import qs from 'querystring'
// let obj ={name:'tom',age:18} //name=tom&age=18 key=value&key=value urlencoded的编码
// console.log(qs.stringify(obj)) //name=tom&age=18
// let str = 'carName=奔驰&price=199'
// console.log(qs.parse(str)); //{carName: '奔驰', price: '199'}
// 在子组件接收需要暂时的参数
const DetailData = [{id:'01',content: '你好,中国'},{id:'02',content: '你好,尚硅谷'},{id:'03',content: '你好,未来的自己'},
]
export default class Detail extends Component {render() {console.log(this.props);//接受params参数// const {id,title} = this.props.match.params// 接收search参数// const {search} = this.props.location// const {id,title} = qs.parse(search.slice(1))//接收state参数const {id,title} = this.props.location.state || {}const findResult = DetailData.find((detailObj)=>{return detailObj.id === id}) || {}return (<ul><li>ID: {id}</li><li>TITLE: {title}</li><li>CONTENT: {findResult.content}</li></ul>)}
}
清除历史记录之后(在浏览器中清除)在访问这个网址就会报错了,Uncaught TypeError: Cannot destructure property 'id' of 'this.props.location.state' as it is undefined. 不能读取属性state从undefined中
at Detail.render (index.jsx:22:1)
index.jsx:30Uncaught TypeError: Cannot read properties of undefined (reading 'content') at Detail.render (index.jsx:30:1) 不能读取属性findResult为undefined
使用 || {} 解决,这样就不会报错了
push与replace模式
push与replace的不同
push相当于一种压栈的方式,不替换任何的路径,点击一个记录一个,留下痕迹
给所有路由链接加上replace之后,就不会加上任何记录
开启了replace之后,就是返回之后直接退回到News,而不是退回到message路径
编程式路由导航
pages/Home/News/index.jsx
import React, { Component } from 'react'export default class News extends Component {// componentDidMount(){// console.log('111');// setTimeout(()=>{// console.log('111');// this.props.history.push('/home/message')// }, 2000)// }render() {return (<ul><li>news001</li><li>news002</li><li>news003</li></ul>)}
}
pages/Home/Message/index.jsx
import React, { Component } from "react";
import {Link,Route} from 'react-router-dom'
import Detail from './Detail'
export default class Message extends Component {state = {messageArr: [{ id: '01', title: '消息1' },{ id: '02', title: '消息2' },{ id: '03', title: '消息3' }]}replaceShow = (id,title) =>{// replace跳转+携带params参数//编写一段代码,让其实现跳转到Detail组件,且为replace跳转、// this.props.history.replace(`/home/message/detail/${id}/${title}`)//replace跳转+携带search参数// this.props.history.replace(`/home/message/detail/?id=${id}&title=${title}`)//replace跳转+携带state参数this.props.history.replace('/home/message/detail',{id,title})}pushShow = (id,title) =>{//编写一段代码,让其实现跳转到Detail组件,且为push跳转、// push跳转+携带params参数// this.props.history.push(`/home/message/detail/${id}/${title}`)// push跳转+携带search参数// this.props.history.push(`/home/message/detail/?id=${id}&title=${title}`)//replace跳转+携带state参数this.props.history.push('/home/message/detail',{id,title})}back = () =>{this.props.history.goBack()}goForward = () =>{this.props.history.goForward()}go = () =>{this.props.history.go(-2)}render() {const { messageArr } = this.statereturn (<div><ul>{messageArr.map((msgObj) => {return (<li key={msgObj.id}>{/* 模板字符串是js里面的东西,所以要使用{``},模板字符串里面要混入,就写{} */}{/* 这样写相当于模糊匹配,上面多,下面少,下面没有接收到 */}{/* 向路由组件传递params参数 */}{/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}{/* 向路由组件传递search参数 */}{/* <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */}{/* 向路由组件传递state参数 */}{/* 这种方式传递数据刷新数据不会丢失 */}<Link to={{pathname: '/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link> <button onClick={()=>this.pushShow(msgObj.id,msgObj.title)}>push查看</button><button onClick={()=>this.replaceShow(msgObj.id,msgObj.title)}>replace查看</button></li>)})}</ul><hr />{/* 声明接受params参数,前面是path值,后面是传递的id */}{/* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}{/* search参数无需声明接收、正常注册路由即可 */}{/* <Route path="/home/message/detail" component={Detail} /> */}{/* state参数无需声明接收、正常注册路由即可 */}<Route path="/home/message/detail" component={Detail} /><button onClick={this.back}>回退</button> <button onClick={this.goForward}>前进</button> <button onClick={this.go}>go</button></div>);}
}
withRouter的使用
components/Header/index.jsx
import React, { Component } from 'react'
import {withRouter} from 'react-router-dom'
// withRouter解决在一般组件当中使用路由组件API
class Header extends Component {back = () =>{this.props.history.goBack() //history是undefined}forward = () =>{this.props.history.goForward()}go = () =>{this.props.history.go(-2)}render() {//如何让this.props拥有historyconsole.log('Header组件收到的props是',this.props); //{}return (<div className="page-header"><h2>React Router Demo</h2><button onClick={this.back}>回退</button> <button onClick={this.forward}>前进</button> <button onClick={this.go}>go</button></div>)}
}
//暴露的是withRouter函数的返回值,作用:withRouter能够接收一个一般组件,然后就把这个一般组件的身上加上了路由组件所特有的那三个属性
export default withRouter(Header)
//withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
// withRouter的返回值是一个新组件
测试代码:
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><!-- 若浏览器不支持js则展示标签中的内容 --><noscript>抱歉!您的浏览器不支持js的运行</noscript><div id="root"></div><script>//1// let obj = { a: 1, b: 2 };// let obj2 = { ...obj, b: 3 };// console.log(obj2);//2// let obj = { a: 1, b: 2 };// delete obj.a;// console.log(obj);//3let obj = { a: { b: { c: 1 } } };let obj2 = { a: { b: 1 } };// console.log(obj.a.b.c);// const {// a: {// b: { c },// },// } = obj;// console.log(c); //1const {a: { b: data },} = obj2;console.log(data);</script></body></html>
额外注意:
按住alt键选中多个方法进行方法定义
安装包的时候最好只使用一种命令,npm i 或者yarn add
前端路由的——history:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>前端路由的基石_history</title>
</head>
<body><a href="http://www.atguigu.com" onclick="return push('/test1') ">push test1</a><br><br><button onClick="push('/test2')">push test2</button><br><br><button onClick="replace('/test3')">replace test3</button><br><br><button onClick="back()"><= 回退</button><button onClick="forword()">前进 =></button><script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script><script type="text/javascript">// let history = History.createBrowserHistory() //方法一,直接使用H5推出的history身上的APIlet history = History.createHashHistory() //方法二,hash值(锚点)function push (path) {history.push(path)return false}function replace (path) {history.replace(path)}function back() {history.goBack()}function forword() {history.goForward()}history.listen((location) => {console.log('请求路由路径变化了', location)})</script>
</body>
</html>
相关文章:
react学习笔记3——基于React脚手架
React路由 相关理解 SPA的理解 单页Web应用(single page web application,SPA)。整个应用只有一个完整的页面。点击页面中的链接不会刷新页面,只会做页面的局部更新。数据都需要通过ajax请求获取, 并在前端异步展现。 路由的理…...
C#中的LINQ:简化数据查询与操作
引言 在现代软件开发中,处理和操作数据是不可避免的任务。无论是从数据库读取信息,还是对内存中的集合进行筛选、排序等操作,开发者都需要一种高效且易于使用的方法。C#中的LINQ(Language Integrated Query)正是为此而…...
OkHttp3.X 工具类封装:链式调用,支持HTTPS、重试、文件上传【内含常用设计模式设计示例】
OkHttp3.X 工具类封装:链式调用,支持HTTPS、重试、文件上传 基于OkHttp3.X封装,提供链式调用API,简化GET/POST请求,支持HTTPS、自动重试、文件上传等功能,提升开发效率。 在 Android 和 Java 开发中&#x…...
Unity SpriteEditor(精灵图片编辑器)
🏆 个人愚见,没事写写笔记 🏆《博客内容》:Unity3D开发内容 🏆🎉欢迎 👍点赞✍评论⭐收藏 🔎SpriteEditor: 精灵图片编辑器 📌用于编辑2D游戏开发中使用的Sp…...
雅思写作--70个高频表达
文章目录 1. learn new skills学生通过户外活动学到很多新技2. take immediate action to do各国采取有效行动以保护环境政府采取了必要行动以减少失业。你应该立即采取行动来解3. communication skills4. grow significantly5. have many advantages1. learn new skills “lea…...
Anaconda中配置Pyspark的Spark开发环境
Anaconda中配置Pyspark的Spark开发环境 目录 1.在控制台中测试ipython是否启动正常2.安装好Java3.安装Spark并配置环境变量4.PySpark配置5.修改spark\conf下的spark-env文件6.测试Pyspark是否安装成功 1.在控制台中测试ipython是否启动正常 anaconda正常安装 这里先检查ipyt…...
Spring 提供了多种依赖注入的方式
构造器注入(Constructor Injection) 构造器注入是通过类的构造函数来注入依赖项。这是 Spring 推荐的方式,因为它提供了不可变性和更好的可测试性。 import org.springframework.stereotype.Component;Component public class ServiceA {pub…...
面经-计算机网络——OSI七层模型与TCP/IP四层模型的对比详解
OSI七层模型与TCP/IP四层模型的对比详解 一、图示解析:分层封装结构 你提供的图清晰展示了网络通信中从应用层到物理层的封装过程,每一层都会对上层的数据加上自己的头部信息(Header): 应用层: 应用…...
网络安全知识问答微信小程序的设计与实现
网络安全知识问答微信小程序的设计与实现,说白了,就是搭建一款网络安全知识问答微信小程序,类似网络安全百科直通车。三步走。 需求沟通 进行需求沟通,此处省略1000字。 画草图 根据沟通的需求,进行整理,…...
Canvas特效实例:黑客帝国-字母矩阵(字母雨)
黑客帝国-字幕矩阵(字母雨) 效果预览代码实现思路解析遗留问题 效果预览 话不多说,我们直接上效果:当页面加载完成,屏幕上会落下如瀑布般的绿色字母流,不断向下滑动,仿佛进入了黑客帝国的数字世…...
「Mac畅玩AIGC与多模态11」开发篇07 - 使用自定义名言插件开发智能体应用
一、概述 本篇介绍如何在 macOS 环境下,通过编写自定义 OpenAPI Schema,将无需认证的名言服务接入 Dify 平台,并开发基于外部公共数据的智能体应用。本案例继续实践 GET 请求型 API 的实际调用技巧。 二、环境准备 1. 确认本地开发环境 macOS 系统Dify 平台已部署并可访问…...
快速上手非关系型数据库-MongoDB
简介 MongoDB 是一个基于文档的 NoSQL 数据库,由 MongoDB Inc. 开发。 NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。 MongoDB 的设计理念是为了应对大数据量、…...
响应式布局,在飞帆平台中如此简单
这些控件都是可以自己动手去实现的。也可以将这些控件复制到自己名下进行修改。 响应式布局https://fvi.cn/782...
UN R79 关于车辆转向装置形式认证的统一规定(正文部分1)
UN R79法规是针对转向装置的型式认证法规,涉及A/B1/C类的横向控制辅助驾驶功能,对各功能的功能边界、性能要求、状态提示、故障警示以及型式认证要提交的信息做了规范,本文结合百度文心一言对法规进行翻译,并结合个人理解对部分内…...
深度学习系统学习系列【1】之基本知识
文章目录 说明基础知识人工智能、机器学习、深度学习的关系机器学习传统机器学习的缺陷选择深度学习的原因深度学习的关键问题深度学习的应用深度学习的加速硬件GPU环境搭建主流深度学习框架对比 说明 文章属于个人学习笔记内容,仅供学习和交流。内容参考深度学习原…...
python3GUI--视频监控管理平台 By:PyQt5(详细讲解)
文章目录 一.前言二.相关知识1.PyQt52.RTSP协议📌 简介:🧩 特点:📡 工作方式: 2. **RTMP(Real-Time Messaging Protocol)**📌 简介:&a…...
第十一届蓝桥杯 2020 C/C++组 既约分数
目录 题目: 题目描述: 题目链接: 思路: 核心思路: 思路详解: 代码: 代码详解: 题目: 题目描述: 题目链接: 既约分数 - 蓝桥云课 思路&a…...
如何让Steam下载速度解除封印?!
平时一直没注意到家里的路由器在偷懒。最近成功榨干家里的带宽,把平时一直20mb/s左右下载速度的路由器一番改造后成功steam下载速度稳定85Mb/s。平时一直都只发挥了他的1/3不到,真是太可惜了。 硬件 首先检查硬件,就千兆路由器而言…...
HOOK上瘾思维模型——AI与思维模型【88】
一、定义 HOOK上瘾思维模型是一种通过设计一系列的触发(Trigger)、行动(Action)、奖励(Reward)和投入(Investment)环节,来促使用户形成习惯并持续使用产品或服务的思维框…...
基于开源AI智能名片链动2+1模式S2B2C商城小程序的IP开发泡沫破局与价值重构研究
摘要:当前IP开发领域普遍存在"冒进式泡沫"现象,企业将初级IP包装为超级IP运营,导致资源错配与价值虚化。本文通过实证分析开源AI智能名片链动21模式S2B2C商城小程序的技术架构与商业逻辑,揭示其通过智能内容引擎、合规化…...
深⼊理解指针(8)
1.对上一篇的补充内容 typedef int* ptr_t #define PTR_T int* 这两种写法都是可以的 ptr_t p1, p2; //p1, p2 都是指针变量 PTR_T p3, p4; //p3 是指针变量, p4是整型变量 为什么p3 是指针变量, p4是整型变量呢? 因为PTR_T 真的被改为了 int* 在编译器中…...
【iview】icon样式
A. 工程中引入样式文件 iview源码工程中的example工程中如何引入iview样式 image.png 自定义工程中如何引入iview样式 一般在src/main.js中引入(在index.html中也可以,当然app.vue中也可以) import "iview/dist/styles/iview.css"B…...
【计算机视觉】三维视觉:Nerfstudio:模块化神经辐射场框架的技术突破与实战指南
深度解析Nerfstudio:模块化神经辐射场框架的技术突破与实战指南 技术架构与核心创新系统架构设计关键技术特性 环境配置与安装指南硬件要求全平台安装流程 实战全流程解析1. 数据采集与预处理2. 模型训练与优化3. 可视化与导出 核心技术深度解析1. 混合表示网络2. 渐…...
第二章 OpenCV篇-图像阈值的综合操作-Python
目录 一.图像阈值 二.图像平滑 1.均值滤波 2.方框滤波 3.高斯滤波 4.中值滤波 5.双边滤波 此章节主要讲解:图像阈值、图像平滑处理、均值滤波、方框滤波、高斯滤波、中值滤波、双边滤波。 这里先讲作者使用matplotlib模块出现错误的解决方法。 首先作者在这…...
WPF处理大规模激光数据计算与安全传输处理
WPF大规模激光数据处理与安全传输系统设计方案 一、系统架构设计 1. 整体架构 ┌─────────────────────────────────────────────┐ │ WPF客户端应用 │ ├───────────────┬…...
vue 常见ui库对比(element、ant、antV等)
Element UI 1. 简介 Element UI 是一个基于 Vue 2 和 Vue 3 的企业级 UI 组件库,提供了丰富的组件和主题定制功能。官方网站:Element UI 2. 主要特点 丰富的组件:包括表单、表格、布局、导航、弹窗等多种组件。主题定制:支持主…...
【c++】【STL】stack详解
目录 stack类的作用什么是容器适配器stack的接口构造函数emptysizetoppushpopswap关系运算符重载 stack类的实现 stack类的作用 stack是stl库提供的一种容器适配器,也就是我们数据结构中学到的栈,是非常常用的数据结构,特点是遵循LIFO&#…...
单片机-89C51部分:12 pwm 呼吸灯 直流电机
飞书文档https://x509p6c8to.feishu.cn/wiki/JkzfwSoFBiUKc4kh8IoccTfyndg 一、什么是PWM? PWM是脉冲宽度调制的缩写,它是一种通过调整脉冲信号的高电平和低电平时间比例来控制电路输出的技术。简单来说,PWM是一种控制电子设备输出电压或电…...
WPF实现数据库操作与日志记录
1. 数据库操作实现 1.1 数据库连接基类 public abstract class DatabaseBase : IDisposable {protected string ConnectionString { get; }protected IDbConnection Connection { get; private set; }protected DatabaseBase(string connectionString){ConnectionString = co…...
用spring-boot-maven-plugin打包成单个jar有哪些缺点优化方案
Spring Boot 的 Fat JAR(通过 spring-boot-maven-plugin 打包)虽然简化了部署,但也存在一些潜在缺点,需根据场景权衡: 1. 启动速度较慢 原因: Fat JAR 需要在启动时解压并加载所有依赖的 JAR 文件到类路径…...
Spring Boot 使用 WebMagic 爬虫框架入门
1. 创建 Spring Boot 项目 使用 Spring Initializr 创建一个 Spring Boot 项目,选择需要的依赖,如 Spring Web 等。 2. 添加 WebMagic 依赖 在项目的 pom.xml 文件中添加 WebMagic 的核心和扩展依赖: <dependency><groupId>u…...
【软件设计师:复习】上午题核心知识点总结(二)
一、计算机网络(常考) 1.网络模型与协议(必考) 1.OSI七层模型 vs. TCP/IP四层模型 OSI七层TCP/IP四层核心协议/设备功能应用层(Application)应用层HTTP、FTP、DNS、SMTP提供用户接口和服务表示层(Presentation)SSL/TLS、JPEG、ASCII数据格式转换、加密/解密会话层(S…...
TensorRt10学习第一章
建立TensorRt时必须要有Public ILogger,因为createInferBuiler和createruntime要用,是一个接口 出错打印 和...
【LeetCode Hot100】回溯篇
前言 本文用于整理LeetCode Hot100中题目解答,因题目比较简单且更多是为了面试快速写出正确思路,只做简单题意解读和一句话题解方便记忆。但代码会全部给出,方便大家整理代码思路。 46. 全排列 一句话题意 给定一个无重复数字的序列…...
Go 语言中一个功能强大且广泛使用的数据验证库github.com/go-playground/validator/v10
github.com/go-playground/validator/v10 是 Go 语言中一个功能强大且广泛使用的数据验证库,主要用于对结构体字段进行数据校验,确保数据的合法性和完整性。以下是其核心作用、使用场景及代码案例的详细说明: 核心作用 数据校验 支持对结构体…...
Java 多线程进阶:线程安全、synchronized、死锁、wait/notify 全解析(含代码示例)
在 Java 并发编程中,“线程安全” 是核心议题之一。本文将深入讲解线程安全的实现手段、synchronized 的使用方式、可重入锁、死锁的成因与避免、wait/notify 通信机制等,并配合实际代码案例,帮助你彻底搞懂 Java 线程协作机制。 一、线程安全…...
windows电脑端SSH连接开termux的安卓端
(确保你此前已经安装好了ssh)在手机termux当中输入: 查看状态:ssh 启动服务:sshd 查看IP:ifconfig 然后在电脑端:...
Java 期中考试练习题
一、引言 Java 作为一门广泛应用的编程语言,在计算机相关专业的课程体系中占据重要地位。期中考试是检验同学们对 Java 知识掌握程度的重要环节。本文将呈现一些典型的 Java 期中考试试题,并进行详细讲解,希望能帮助大家更好地理解和掌握 Ja…...
【Unity】 组件库分类详解
1️⃣ Audio(音频组件) 用于处理游戏中的声音。 Audio Source 读音[ˈɔːdiəʊ ˈsɔːs],音频源组件,用于播放音频文件,可设置音量、Pitch、循环播放等属性,是音频播放的核心组件。 Audio Listener 读音…...
Java 中使用正则表达式
1. 引入包 在使用正则表达式之前,需要引入包: import java.util.regex.Matcher; import java.util.regex.Pattern; 2. 常用模式规则 元字符 :这些是正则表达式中的特殊字符,用于匹配特定的模式。 . :匹配任意单个字…...
如何降低LabVIEW开发费用
在 LabVIEW 开发过程中,开发费用是用户和开发者共同关注的重点。过高的开发成本可能会压缩项目利润空间,甚至影响项目的可行性。下面将介绍降低 LabVIEW 开发费用的有效方法。 合理规划项目需求,避免后期增加 在项目启动阶段ÿ…...
WPF使用SQLSugar和Nlog
WPF应用中使用SQLSugar和NLog实现数据库操作与日志记录 1. 准备工作 首先,通过NuGet安装必要的包: Install-Package SQLSugarCore Install-Package NLog Install-Package NLog.Config Install-Package NLog.Targets.File 2. 配置NLog 在项目中添加nlog.config文件: <…...
Python10天冲刺-设计模型之策略模式
策略模式是一种行为设计模式,它允许你在运行时动态地改变对象的行为。这种模式的核心思想是将一组相关的算法封装在一起,并让它们相互替换。 下面是使用 Python 实现策略模式的一个示例: 示例代码 假设我们有一个简单的购物车系统…...
Js扩展DOM、BOM、AJAX、事件、定时器
BOM 操作 BOM指的是浏览器对象模型:Browser Object Mode,通过操作 window 对象的属性和方法来实现与浏览器的交互。 BOM的构成如下图所示: 其中,window对象是顶级对象,在 window 对象下面有一些重要的属性࿱…...
奥地利学派方法论的三个基础
主观价值论: 一切估价行为皆来自于个人,价格现象只能从主观估价中得到解释。 个人只在边际上做决策,边际价值是递减的。 罗斯巴德的等式:三个单位的某个东西的总效用 > 两个单位的总效用 > 一个单位的总效用,但…...
WPF之Image控件详解
文章目录 1. 概述2. Image控件的基本属性2.1 Source属性2.2 Stretch属性2.3 StretchDirection属性 3. 在XAML中使用Image控件3.1 基本用法3.2 设置拉伸模式3.3 设置图像对齐方式 4. 在代码中操作Image控件4.1 加载本地图像4.2 异步加载图像4.3 从流中加载图像4.4 控制图像的解码…...
如何将 VS Code 与 Linux 系统高效连接:从入门到进阶
引言 无论是开发服务器应用、管理远程主机,还是在本地 Linux 环境中提升开发效率,Visual Studio Code(VS Code) 凭借其强大的扩展能力,成为连接 Linux 系统的利器。本文将详细介绍 三种主流方法,助你无缝对…...
Matlab/Simulink - BLDC直流无刷电机仿真基础教程(五) - animateRotorPosition脚本讲解与使用
Matlab/Simulink - BLDC直流无刷电机仿真基础教程(五) - animateRotorPosition脚本讲解与使用 前言一、animateRotorPosition脚本内容二、脚本功能讲解三、脚本修改与模型配置四、可视化效果展示五、修改后脚本内容文章相关模型文件下载链接参考链接 前言…...
安川机器人常见故障报警及解决办法
机器人权限设置 操作权限设置(如果密码不对,就证明密码被人修改) 编辑模式密码:无(一把钥匙,默认) 管理模式密码:999999999(9个9,二把钥匙) 安全模式密码:555555555(9个5,三把钥匙,权限最高,有的型号机器人,没有此模式,但最高密码为安全模式密码) 示教器…...
【Quest开发】极简版!透视环境下抠出身体并能遮挡身体上的服装
前两天发了一个很复杂的版本,又鼓捣了一下发现完全没有必要。我之前的理解有点偏(不是错误的但用法错了),但是有一些小伙伴收藏了,害怕里面的某些东西对谁有用,所以写了一篇新的,前两步配置环境…...