4

react router页面跳转二次确认弹框及样式、业务逻辑自定义

 3 years ago
source link: https://www.daozhao.com/10028.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

react router页面跳转二次确认弹框及样式、业务逻辑自定义

如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!

react router页面跳转二次确认弹框及样式、业务逻辑自定义

我们在编辑页面时如果需要跳走通常会需要给用户提示,react router本身已经给了我们这样的功能,我们先看看怎么使用。

初见二次确认弹框
// App.jsx
const App = () {
    return (
      <BrowserRouter>
        <div>
          <ul style={{marginTop: '10px'}}>
            <li>
              <Link to='/'>Home</Link>
            </li>
            <li>
              <Link to='/write'>Write</Link>
            </li>
          </ul>
          <Switch>
            <Route exact path='/'>
            </Route>
            <Route path='/write' strict={true} forceRefresh={true} component={WriteMail}>
            </Route>
          </Switch>
        </div>
      </BrowserRouter>
      );
}
export default App;

在WriteMail组件里面我们加上Prompt组件并且设置whentrue,就会有二次确认弹框了,也就是从/write页面跳转时会需要进行确认

// WriteMail.jsx
const WriteMail = () => {
    function redirectMsg(location, type) {
      return type + ': Go to ' + location.pathname;
    }

    return (
        <div>
          <h1>Write</h1>
          <Prompt when={true} message={(a) => redirectMsg(a,  '外层')}></Prompt>
        </div>
    );
};
export default WriteMail;

效果如下 file

自定义二次确认弹框

功能是有了,但是界面也太丑了吧。不用担心,react router当然支持自定义二次弹框啊。

我们的二次确认弹框其实通过给BrowserRouter(或者HashRouter)组件设置属性来自定义的,它默认的就是window.confirm

官方是这么说的

<BrowserRouter
  getUserConfirmation={(message, callback) => {
    // this is the default behavior
    const allowTransition = window.confirm(message);
    callback(allowTransition);
  }}
>
</BrowserRouter>

所以我们需要修改下App.jsx了,我们这里引入antd的Modal做弹框

// App.jsx
const App = () {
    const getUserConfirmation = (message, callback) => {
        Modal.confirm({
          title: '提示',
          content: '您即将放弃编辑邮件,是否需要将当前内容保存为草稿?',
          cancelText: '不保存',
          okText: '保存草稿',
          onCancel: () => {
            callback(false);
          },
          onOk: () => {
            callback(true);
          }
        });
    }
    return (
      <BrowseRrouter>
        <div>
          <ul style={{marginTop: '10px'}}>
            <li>
              <link to='/'/>Home
            </li>
            <li>
              <link to='/write'/>Write
            </li>
          </ul>
          <Switch>
            <Route exact path='/'>
            </Route>
            <Route path='/write' strict={true} forceRefresh={true} component={WriteMail}>
            </Route>
          </Switch>
        </div>
      </BrowseRrouter>
      );
}
export default App;

file 是不是很完美?

这个getUserConfirmation属性是在BrowserRouter组件上的,一般我们的项目可能只在组件树的外层才会有一层BrowserRouter,而业务组件一般是在其里面的Route组件的里面,即

<BrowseRrouter getUserConfirmation={getUserConfirmation}>
     <Switch>
         <Route>
            <WriteMail></WriteMail>
         </Route>
     </Switch>
</BrowseRrouter>

如果我们需要在getUserConfirmation里面出来当前WriteMail相应的业务逻辑怎么弄?(比如弹框提示文案是“您即将跳转,是否需要保存草稿?”,我们需要执行WriteMail里面的保存草稿逻辑。)

我们很容易想到,如果能将Router组件,放到WriteMail里面就好了,那样我们就能将getUserConfirmation写在WriteMail,执行对应的逻辑就很容易了。

我们尝试下在WriteMail加一层BrowserRouter,同时需要将业务逻辑(编辑组件)放置于内层的Route下,即多了一层路由

// WriteMail.jsx
function WriteMail(props) {
  const [value, setValue] = useState('');

  const getUserConfirmationInWrite = (message, callback) => {
    Modal.confirm({
      title: message,
      onCancel: () => {
        callback(false);
      },
      onOk: () => {
        callback(true);
      }
    });
  }

  return (
    <div>
      <h1>Write</h1>
      <Prompt when={true} message={(a) => redirectMsg(a,  '外层')}></Prompt>

      <ul style={{marginTop: '10px'}}>
        <li>
          <link to='/write/first'/>First
        </li>
        <li>
          <link to='/write/second'/>Second
        </li>
      </ul>

      <BrowserRouter getUserConfirmation={getUserConfirmationInWrite}>
        <Route path='/write/first'>
          <h3>first</h3>
          <Prompt when={true} message={(a) => redirectMsg(a, '内层')}></Prompt>
          <button>count: {count}</button>
          <input type='text' placeholder='write' value={value} onChange={(e) =/> setValue(e.target.value)}/>
        </Route>
        <Route path='/write/second'>
          <h3>second</h3>
        </Route>
      </BrowserRouter>
    </div>
  )
}

现在我们有两层路由了,我们可以设置成不同的getUserConfirmation ,同时也将文案改了改,外层的表示第一层路由的提示,内层表示第二层。App.jsx用默认的getUserConfirmationwindow.confirm

完整的代码如下

// App.jsx
const App = () {
    return (
      <BrowserRouter>
        <div>
          <ul style={{marginTop: '10px'}}>
            <li>
              <Link to='/'>Home</Link>
            </li>
            <li>
              <Link to='/write'>Write</Link>
            </li>
          </ul>
          <Switch>
            <Route exact path='/'>
            </Route>
            <Route path='/write' strict={true} forceRefresh={true} component={WriteMail}>
            </Route>
          </Switch>
        </div>
      </BrowserRouter>
      );
}
export default App;
// WriteMail.jsx
function WriteMail(props) {
  const [value, setValue] = useState('');
  const [count, setCount] = useState(0);

function redirectMsg(location, type = 0) {
  return type + ': Go to ' + location.pathname;
}

  const getUserConfirmationInWrite = (message, callback) => {
    console.log('getUserConfirmationInWrite -> ', );
    Modal.confirm({
      title: message,
      onCancel: () => {
        setCount(count => count - 1);
        callback(false);
      },
      onOk: () => {
        setCount(count + 1);
        callback(true);
      }
    });
  }

  return (
    <div>
      <h1>Write</h1>
      <Prompt when={true} message={(a) => redirectMsg(a,  '外层')}></Prompt>

      <ul style={{marginTop: '10px'}}>
        <li>
          <Link to='/write/first'>First</Link>
        </li>
        <li>
          <Link to='/write/second'>Second</Link>
        </li>
      </ul>

      <Router getUserConfirmation={getUserConfirmationInWrite}>
        <Route path='/write/first'>
          <h3>first</h3>
          <Prompt when={true} message={(a) => redirectMsg(a, '内层')}></Prompt>
          <button>count: {count}</button>
          <input type='text' placeholder='write' value={value} onChange={(e) => setValue(e.target.value)}/>
        </Route>
        <Route path='/write/second'>
          <h3>second</h3>
        </Route>
      </Router>
    </div>
  )
}
export default WriteMail;

现在我们在WriteMail里面的getUserConfirmationInWrite就可以写组件内的业务逻辑(setCount)了。

上面的代码里面我们有两个Prompt,分别表示从/write开头的路径/write/first路径跳转时会进行二次确认。 实测发现:

  1. /write切换至/write/first,会有外层提示,从 并且我们可以看到外层提示
  2. /write/first切换至/write,会先有外层提示,点击确认后再出现内层提示;如果外层提示时点击了取消,则不会再有内层提示了。 file

file

PS: 我们会发现在点击二次确认时浏览器的url可能已经提前变更了,及时在二次确认弹框时点击的是取消,但是好在内容是带确认后才会变更。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK