react 的 router && rem解决方案&& antd-mobile组件库在React中的使用@stage3---week5--day3

  • react 的 router
  • rem
  • 使用组件库 antd-mobile

react 的 router

先构建页面
  1. 目录

    • components 公用组件
    • layout 布局组件
    • utils 封装工具 rem request
    • pages/views 路由对应的页面
  2. 移动端是要配置自适应的 rem + 弹性盒

  • 淘宝方案

    • https://github.com/amfe/lib-flexible
    /* 
      通过js来动态添加rem 
    */
    
    (function(designWidth, maxWidth) {
      var doc = document,
        win = window,
        docEl = doc.documentElement,
        remStyle = document.createElement("style"),
        tid;
    
      function refreshRem() {
        var width = docEl.getBoundingClientRect().width;
        maxWidth = maxWidth || 540;
        width > maxWidth && (width = maxWidth);
        var rem = (width * 100) / designWidth;
        remStyle.innerHTML = "html{font-size:" + rem + "px;}";
      }
    
      if (docEl.firstElementChild) {
        docEl.firstElementChild.appendChild(remStyle);
      } else {
        var wrap = doc.createElement("div");
        wrap.appendChild(remStyle);
        doc.write(wrap.innerHTML);
        wrap = null;
      }
      //要等 wiewport 设置好后才能执行 refreshRem,不然 refreshRem 会执行2次;
      refreshRem();
    
      win.addEventListener(
        "resize",
        function() {
          clearTimeout(tid); //防止执行两次
          tid = setTimeout(refreshRem, 300);
        },
        false
      );
    
      win.addEventListener(
        "pageshow",
        function(e) {
          if (e.persisted) {
            // 浏览器后退的时候重新计算
            clearTimeout(tid);
            tid = setTimeout(refreshRem, 300);
          }
        },
        false
      );
    
      if (doc.readyState === "complete") {
        doc.body.style.fontSize = "16px";
      } else {
        doc.addEventListener(
          "DOMContentLoaded",
          function(e) {
            doc.body.style.fontSize = "16px";
          },
          false
        );
      }
    })(375, 750);
    
    // 备注: 这里的375本身就应该写成750 ,但是写成750之后,我们设计稿的尺寸要/50,不好算,我就想,除以100更好算,所以我改成了375
    
  • 网易方案

    function font() {
      document.documentElement.style.fontSize =
        document.documentElement.clientWidth / 3.75 + "px";
    }
    
    font();
    
    window.onresize = font;
    
  • 阿里 rem

    (function(doc, win) {
      const docEl = doc.documentElement,
        resizeEvt =
          "orientationchange" in window ? "orientationchange" : "resize",
        recalc = function() {
          const clientWidth = docEl.clientWidth;
          if (!clientWidth) return;
          let max = 24;
          let min = 9.3125;
          let size = 20 * (clientWidth / 320);
    
          size = Math.min(size, max);
          size = Math.max(size, min);
          docEl.style.fontSize = size + "px";
          console.log(docEl.style.fontSize, "em= =====");
        };
      if (!doc.addEventListener) return;
      win.addEventListener(resizeEvt, recalc, false);
      doc.addEventListener("DOMContentLoaded", recalc, false);
    })(document, window);
    
sass

注意: sass 文件之间引用使用@import , 在路径上还得加一个~
@import ‘~/…/…/…/assets/global_style/theme.scss’;

router

import React, { useState, Fragment } from "react";
import "./index.scss";
import { NavLink, BrowserRouter } from "react-router-dom";

function Tabbar() {
  const [list] = useState([
    //? tabbar 的数据
    {
      id: 1,
      text: "首页",
      className: "fa-home",
      path: "/home"
    },
    {
      id: 2,
      text: "分类",
      className: "fa-th-large",
      path: "/category"
    },
    {
      id: 3,
      text: "购物车",
      className: "fa-shopping-cart",
      path: "/shopcar"
    },
    {
      id: 4,
      text: "我的",
      className: "fa-user-o",
      path: "/mine"
    }
  ]);

  function renderTabbarItem() {
    //? 渲染列表函数
    return list.map(elm => (
      <li key={elm.id}>
        {/* <BrowserRouter> */}
        <NavLink to={elm.path}>
          <div>
            <i className={"fa " + elm.className}></i>
          </div>
          <div>{elm.text}</div>
        </NavLink>
        {/* </BrowserRouter> */}
      </li>
    ));
  }
  return (
    <Fragment>
      <footer>
        <ul>{renderTabbarItem()}</ul>
      </footer>
      {/* <i className="fa fa-home"></i>
            <i className="fa fa-user-o"></i>
            <i className="fa fa-shopping-cart"></i>
            <i className="fa fa-th-large"></i> */}
    </Fragment>
  );
}

export default Tabbar;

XXX

import React, { useState } from "react";
import { Route, Switch, Redirect, BrowserRouter } from "react-router-dom";
import Home from "../views/home";
import Category from "../views/category";
import Shopcar from "../views/shopcar";
import Mine from "../views/mine";

function RouterComp() {
  const [routes] = useState([
    {
      id: 1,
      path: "/home",
      component: Home
    },
    {
      id: 2,
      path: "/category",
      component: Category
    },
    {
      id: 3,
      path: "/shopcar",
      component: Shopcar
    },
    {
      id: 4,
      path: "/mine",
      component: Mine
    }
  ]);

  function renderRoutes() {
    return routes.map(item => (
      <Route
        key={item.id}
        path={item.path}
        component={item.component}
        exact={item.exact}
      ></Route>
    ));
  }
  return (
    //* Route是一个路由展示组件,通过component属性来确定渲染哪一个组件
    //* Switch组件一次只渲染一个Route
    // * 可以实现类似按需加载组件的作用,可以起到一定的性能优化作用
    //* exact 是路由完全匹配
    //* Redirect 是重定向组件  from 来源  to 目标     /  /home
    // <BrowserRouter>
    <Switch>
      <Redirect from="/" to="/home" exact></Redirect>
      {renderRoutes()}

      {/* <Router path="/home" component={Home} exact=></Router> */}
    </Switch>
    //{/* </BrowserRouter> */}
    // <Home></Home>
  );
}

export default RouterComp;

  • react-router 5 提供了两种路由形式 HashRouter BrowserRouter
    • HashRouter #/home hashchange 事件 兼容高
    • BrowserRouter /home h5 popchange 事件 兼容低
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";

import { BrowserRouter as Router } from "react-router-dom";
// ? react-router 5提供了两种路由形式 HashRouter  BrowserRouter
// * HashRouter     #/home  hashchange事件       兼容高
// * BrowserRouter  /home   h5 popchange事件     兼容低

ReactDOM.render(
  <Router>
    <App />
  </Router>,
  document.getElementById("root")
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();


React 二级路由如何

在路由对应的组件中写入导航和路由展示区域就行了

// src> category > index.js
import React, { useState } from "react";
import "./index.scss";
import { Route, NavLink, Redirect } from "react-router-dom";
import Picture from "./children/picture";
import Text from "./children/text";
import Comment from "./children/comment";

function Category() {
  const [navLink] = useState([
    {
      id: 1,
      text: "图片",
      path: "/category/picture"
    },
    {
      id: 2,
      text: "文字",
      path: "/category/text"
    },
    {
      id: 3,
      text: "评论",
      path: "/category/comment"
    }
  ]);
  function renderNavLink() {
    return navLink.map(item => {
      return (
        <NavLink to={item.path} key={item.id}>
          {item.text}
        </NavLink>
      );
    });
  }
  return (
    <article className="category-box">
      <section className="category-nav">{renderNavLink()}</section>
      <section className="category-main">
        <h3>列表</h3>
        <Redirect from="/category" to="/category/text" exact></Redirect>
        <Route path="/category/picture" component={Picture}></Route>
        <Route path="/category/text" component={Text}></Route>
        <Route path="/category/comment" component={Comment}></Route>
      </section>
    </article>
  );
}

export default Category;

Switch 的作用是可以延续到二级路由中的

编程式导航 ---- 使用 js 来跳转页面

只有使用了Route的组件身上才有路由属性、

我们想在LayOut组件中监听整个项目路由变化情况,但是LayOut组件不是路由组件
1.什么路由组件?

  • 由Route组件处理的才是路由组件
  1. 分析: 如果能够将LayOut组件变成路由组件那就可以了 ?
  2. 解决: 使用 react-router-dom 提供的 高阶`组件 withRouter , 将LayOut 组件变成伪路由组件
// App.js
import React from 'react';
import './App.scss';
import Layout from './layout/Layout';
import './utils/rem.js'
import { withRouter } from 'react-router-dom'

function App( props ) {
  return (
    <div className="App">
      <Layout {...props}></Layout>
    </div>
  );
}

export default withRouter(App);
//src> layout > index.js
import React from 'react';
import './App.scss';
import Layout from './layout/Layout';
import './utils/rem.js'
import { withRouter } from 'react-router-dom'

function App( props ) {
  return (
    <div className="App">
      <Layout {...props}></Layout>
    </div>
  );
}

export default withRouter(App);
// <!-- src> component> tab> index.js -->
import React from 'react';

import './tab.scss';

// import 'antd-mobile/dist/antd-mobile.css';
function Tab ( props ) {

    function goBack() {
        console.log('goBack')
        props.history.go(-1)
    }

    return (
        <header>
            {props.goback_flag && <i onClick={goBack}>&lt;</i>}
            {/* <i>&lt;</i> */}
            <h3>猫眼电影</h3>
        </header>
    )
}

export default Tab

使用组件库 antd-mobile

  1. 下载 组件库
  2. 安装 antd-mobile -D
 % yarn add antd-mobile -D
  1. 使用#
  • 入口页面 (html 或 模板) 相关设置:

    引入 FastClick 并且设置 html meta (更多参考 #576)
    引入 Promise 的 fallback 支持 (部分安卓手机不支持 Promise)

<!-- public> index.html -->
<!DOCTYPE html>
<html>
  <head>
    <!-- set `maximum-scale` for some compatibility issues -->
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script>
    <script>
      if ("addEventListener" in document) {
        document.addEventListener(
          "DOMContentLoaded",
          function() {
            FastClick.attach(document.body);
          },
          false
        );
      }
      if (!window.Promise) {
        document.writeln(
          '<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"' +
            ">" +
            "<" +
            "/" +
            "script>"
        );
      }
    </script>
  </head>
  <body></body>
</html>
  1. 按需加载
    引入 react-app-rewired 并修改 package.json 里的启动配置:
$ npm install react-app-rewired --save-dev
/* package.json */
"scripts": {
-   "start": "react-scripts start",
+   "start": "react-app-rewired start",
-   "build": "react-scripts build",
+   "build": "react-app-rewired build",
-   "test": "react-scripts test --env=jsdom",
+   "test": "react-app-rewired test --env=jsdom",
}
  1. 然后在项目根目录创建一个 config-overrides.js 用于修改默认配置。
module.exports = function override(config, env) {
  // do stuff with the webpack config...
  return config;
};
  1. 使用 babel-plugin-import, babel-plugin-import 是一个用于按需加载组件代码和样式的 babel 插件(原理),现在我们尝试安装它并修改 config-overrides.js 文件。
% yarn add babel-plugin-import -D
const { override, fixBabelImports, addLessLoader } = require("customize-cra");

module.exports = override(
  fixBabelImports("babel-plugin-import", {
    libraryName: "antd-mobile",
    style: true
  }),
  addLessLoader({
    ident: "postcss",
    javascriptEnabled: true,
    modifyVars: { "@primary-color": "#1DA57A" }
  })
);

注意 : antd 默认引入样式是 less,所以需要手动配置为 CSS,配置方法如下:
第一种方法:在 package.json 中配置,这种方法成功的前提是 webpack 里 query 下配置 babelrc:true, 这样就会使用 babelrc 文件中的配置

"babel": {
    "presets": [
      "react-app"
    ],
    "plugins": [
      [
        "import",
        {
          "libraryName": "antd",
          "style": "css"
        }
      ]
    ]
  }
  1. 第二种方法:在 webpack.config.dev 和 webpack.config.prod 中配置:
module: {
    strictExportPresence: true,
    rules: [
      {
        oneOf: [
          // Process JS with Babel.
          {
            test: /\.(js|jsx|mjs)$/,
            include: paths.appSrc,
            loader: require.resolve('babel-loader'),
            options: {
                plugins: [
                    // 引入样式为 css
                    // style为true 则默认引入less
                    ['import', { libraryName: 'antd', style: 'css' }],
                ]
            }
         }
      ]
    }
  ]
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值