Quartz Filter 高阶函数 循环 firebase azure reference vue的钩子函数 河南普通话考试报名 jquery选择子元素 axure组件库下载 erp项目描述 java 数据分析 如何升级python oracle行转列函数 java上传图片 网页设计公司 普通话网上报名 python中的map函数 python自学入门 python中集合 java查看版本 java自定义异常 java查看变量类型 java绝对值 内存修改器 机械下载 python封装 pr转场特效下载 批处理if 字符串分割成数组 送货单管理系统 sdm439 pr抖动特效 战法装备 夜之魇掉落 ps祛痘 g4560配什么显卡 adb安装 cad打散
当前位置: 首页 > 学习教程  > 编程语言

没有webpack和脚手架的老项目用上React技术栈

2020/12/28 18:38:05 文章标签:

不用 react 脚手架和 webpack,直接使用 react 写 demo 老项目使用 react 技术一直发展,可是总有项目来不及更新。当年 MVC 技术热度不减现在的 react 和 vue。几年过去了,前后端分离,各种前端框架的出现,使得部分老项…

不用 react 脚手架和 webpack,直接使用 react 写 demo

老项目使用 react

技术一直发展,可是总有项目来不及更新。当年 MVC 技术热度不减现在的 react 和 vue。几年过去了,前后端分离,各种前端框架的出现,使得部分老项目更加少人维护了,毕竟 MVC 项目的语法对前端实在是太不友好了

然而最近有一个项目就是 java web 的项目,可是新的需求的 UI 库又是基于 teambition 的,借此机会也顺便学习下 react。

react 可以像 vue 一样 “渐进式” 吗?

vue 可以直接引入 vue 的依赖文件,直接在项目中使用 new Vue() 来生成 vue 的实例,所以就算离开脚手架,也只是写法上的一点小区别
那 react 可以吗?可以!只是不是用 new React 的方式

React 的挂载方式

先看一段代码

class App extends React.Component {}
ReactDOM.render(<App />, document.querySelector('#app'))

这是 React 挂载的方式(当然也可以写 hook)。通过 ReactDOM.render 挂载

所以最重要的就是找到 ReactReactDom 的变量

用 CDN 找一下这 2 个库

值得一提的是:CDN 有非常多的 JS 提供选择,自己可以留意下前缀,和 js 名,调试模式下用 development.js 可以获得一些错误信息。上线的时候改用 production.min.js 库会更小,一些警告之类的也不会出现。

最后我选择了 umd 的
新建一个页面,引入这 2 个库试下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>React demo</title>

    <script
      src="https://cdn.bootcdn.net/ajax/libs/react/17.0.1/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://cdn.bootcdn.net/ajax/libs/react-dom/17.0.1/umd/react-dom.development.js"
      crossorigin
    ></script>
  </head>

  <body>
    <div id="app"></div>
  </body>

  <script>
    class App extends React.Component {
      render() {
        return <div>hello React</div>
      }
    }
    ReactDOM.render(<App />, document.querySelector('#app'))
  </script>
</html>

运行发现报错了,原生的 js 并不认识 jsx 的语法

转义 JS

通过 webpack,我们可以把一些 JS 无法识别的东西,进过 loader 或者各种插件,转换为 JS 能识别的,那现在没 webpack 应该如何转换 jsx?

babel,而且是动态转义

老规矩在 CDN 找到 babel 的库。而且必须是找 离线包 babel-standalone

引入:

<script
  src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"
  crossorigin
></script>

既然引入了 babel。那 script 标签必须改成 <script type="text/babel"> 才能识别

最后代码如下(多加了一些 state 之类的语法):

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>React demo</title>

    <script
      src="https://cdn.bootcdn.net/ajax/libs/react/17.0.1/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://cdn.bootcdn.net/ajax/libs/react-dom/17.0.1/umd/react-dom.development.js"
      crossorigin
    ></script>
    <script
      src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"
      crossorigin
    ></script>
  </head>

  <body>
    <div id="app"></div>
  </body>

  <script type="text/babel">
    class App extends React.Component {
      constructor() {
        super()

        this.state = {
          msg: 'hello React'
        }
      }

      render() {
        let { msg } = this.state
        return <div>{msg}</div>
      }
    }
    ReactDOM.render(<App />, document.querySelector('#app'))
  </script>
</html>

引入 UI 库

下面用 at 这个库作为演示
AT 这个 UI 库非常贴心的提供了 cdn 资源

直接引入

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@txdfe/at/build/teambition.min.css" />
<script src="https://cdn.jsdelivr.net/npm/@txdfe/at/build/at.min.js"></script>

文档中有一句话非常重要

这个库有导出一个AT的全局变量

使用组件

先试下 button 组件把

这段代码肯定不能直接用在我们的项目中,毕竟还有 import。我们也没用 nodejs 安装依赖

不过反过来想,既然 UI 库导出了一个名为 AT 的全局变量。import 也只是到 node_modules 里面帮我们找到对应的库,如果粗暴点翻译为 ES6 长啥样?更加 ES6 解构赋值的语法:
import { Button } from '@txdfe/at'; === const { Button } = AT

<script type="text/babel">
  const { Button } = AT
  class App extends React.Component {
    constructor() {
      super()

      this.state = {
        msg: 'hello React'
      }
    }

    render() {
      let { msg } = this.state
      return <Button>{msg}</Button>
    }
  }
  ReactDOM.render(<App />, document.querySelector('#app'))
</script>

运行成功!

而且基于 React 的语法。我们甚至都不用每次都声明,可以把上面的代码改成这样(为了做对比,我新找了一个组件):

<script type="text/babel">
  const { Button } = AT
  class App extends React.Component {
    constructor() {
      super()

      this.state = {
        msg: 'hello React'
      }
    }

    onChange(checked) {
      console.log(`switch to ${checked}`)
    }

    render() {
      let { msg } = this.state
      return (
        <div>
          <Button>{msg}</Button>
          <AT.Switch onChange={this.onChange} />
        </div>
      )
    }
  }
  ReactDOM.render(<App />, document.querySelector('#app'))
</script>

可以看出,<AT.Switch> 标签可以直接用,而且各种事件也是可以兼容
接下来的写法就和 React 一样了

附上完整的代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>React demo</title>

    <script
      src="https://cdn.bootcdn.net/ajax/libs/react/17.0.1/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://cdn.bootcdn.net/ajax/libs/react-dom/17.0.1/umd/react-dom.development.js"
      crossorigin
    ></script>
    <script
      src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"
      crossorigin
    ></script>

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@txdfe/at/build/teambition.min.css" />
    <script src="https://cdn.jsdelivr.net/npm/@txdfe/at/build/at.min.js"></script>
  </head>

  <body>
    <div id="app"></div>
  </body>

  <script type="text/babel">
    const { Button } = AT
    class App extends React.Component {
      constructor() {
        super()

        this.state = {
          msg: 'hello React'
        }
      }

      onChange(checked) {
        console.log(`switch to ${checked}`)
      }

      render() {
        let { msg } = this.state
        return (
          <div>
            <Button>{msg}</Button>
            <AT.Switch onChange={this.onChange} />
          </div>
        )
      }
    }
    ReactDOM.render(<App />, document.querySelector('#app'))
  </script>
</html>

使用 hook 语法 和 useState

既然 React 能运行起来,hook 语法和 useState 是不是一样可以兼容?

<!-- 新增一个hook挂载节点 -->
<div id="hook"></div>

<!-- 使用hook的语法和 useState -->
<script type="text/babel">
  function App2() {
    const [msg, updateMsg] = React.useState('App2 Demo')
    return (
      <div>
        <AT.Button onClick={() => updateMsg('click btn')}>{msg}</AT.Button>
        <AT.Switch />
      </div>
    )
  }
  ReactDOM.render(<App2 />, document.querySelector('#hook'))
</script>
  • 点击按钮前

  • 点击按钮,使用 updateMsg 更新(注意按钮的文案已经修改了)

之前我们用 import {useState} from 'React' 之类的语法,都可以翻译为 React.xxxx 来使用

使用更多的 UI 库

React 的库还有一个特别喜欢的就是 Ant Design 了

在官方文档上没给出 CDN 的地址,所以还是到 boot CDN 上找 bootcdn - antd

CDN 上也是有非常多的资源,其中包括不少样式库等,我们先只引入最基础的 js 和 css

引入后,我们打印一下 window.antxxx(这时候浏览器会有提示的,根据提示我们知道了是 window.antd)

看下我们发现了什么,虽然 antd 是个 Module 对象(应该是给 import 那些用的)。可是这并不影响我们取组件!老规矩来一段 Button

<script type="text/babel">
  function AntdDemo() {
    return (
      <div>
        <antd.Button type="primary">Primary Button</antd.Button>
        <antd.Button>Default Button</antd.Button>
        <antd.Button type="dashed">Dashed Button</antd.Button>
        <br />
        <antd.Button type="text">Text Button</antd.Button>
        <antd.Button type="link">Link Button</antd.Button>
      </div>
    )
  }
  ReactDOM.render(<AntdDemo />, document.querySelector('#antddemo'))
</script>

自定义组件该如何引入呢

我们自定义了一个组件,并且接受传入的参数,外层按钮进行触发更新

  • myComponents.js
function MyCompoents(props) {
  return <div>{props.msg}</div>
}
  • demo 的写法:
<!-- 引入我们的组件 -->
<script src="./myComponents.js" type="text/babel"></script>

<!-- 在demo中更新 -->
<script type="text/babel">
  function AntdDemo() {
    const [msg, updateMsg] = React.useState('App2 Demo')
    return (
      <div>
        <antd.Button type="primary">Primary Button</antd.Button>
        <antd.Button>Default Button</antd.Button>
        <antd.Button type="dashed">Dashed Button</antd.Button>
        <br />
        <antd.Button type="text">Text Button</antd.Button>
        <antd.Button type="link">Link Button</antd.Button>

        <br />

        <br />

        <br />

        {/* 这就是我们自定义的组件 */}
        <MyCompoents msg={msg}></MyCompoents>

        <antd.Button type="primary" onClick={() => updateMsg('更新组件props')}>
          更新组件文案
        </antd.Button>
      </div>
    )
  }
  ReactDOM.render(<AntdDemo />, document.querySelector('#antddemo'))
</script>

填坑时间

全局变量的问题

一路写下来,是不是觉得没毛病?项目就这样用上了 React !!
不,还漏了一个最重要的东西,全局变量

无论我们写的 hook 还是 class 的方式,我们都是直接声明,这意味着这是一个全局的变量。如果用脚手架或者 webpack,我们还能通过 export 的方法去相互隔离,但是这里没有啊~

想解决也很简单,只需要包一层方法,让他们相互隔离

像这样,使用一个立即执行函数,让 App 只留在这个立即执行的函数内部,这样就不会污染全局变量了。

;(function() {
  function App() {
    const [msg, updateMsg] = React.useState('App2 Demo')
    return (
      <div>
        <antd.Button type="primary">Primary Button</antd.Button>
        <antd.Button>Default Button</antd.Button>
        <antd.Button type="dashed">Dashed Button</antd.Button>
        <br />
        <antd.Button type="text">Text Button</antd.Button>
        <antd.Button type="link">Link Button</antd.Button>

        <br />

        <br />

        <br />

        <MyCompoents msg={msg}></MyCompoents>

        <antd.Button type="primary" onClick={() => updateMsg('更新组件props')}>
          更新组件文案
        </antd.Button>
      </div>
    )
  }
  ReactDOM.render(<App />, document.querySelector('#antddemo'))
})()

组件的全局变量问题如何解决?如果是公共的自定义组件,要通过 script 引入啊

是的,公共组件需要通过 script 变量引入,如果这时候用函数在包裹着组件,那我们引入 JS 后也拿不到组件

这时候就可以参考 UI 库的做法,我们只暴露一个全局的名称:比如 AT,或者 antd。那自己项目规定好名字就行

注意这里,我们把全局的组件都放在 My 变量中。而且每次 JS 引入的时候,都判断 My 是否存在
然后在往 My 中添加我们的组件 MyCompoents

window.My = window.My || {}
;(function() {
  My.MyCompoents = function(props) {
    return <div>{props.msg}</div>
  }
})()

使用的时候 <My.MyCompoents></My.MyCompoents>

<script type="text/babel">
  function AntdDemo() {
    const [msg, updateMsg] = React.useState('App2 Demo')
    return (
      <div>
        <My.MyCompoents msg={msg}></My.MyCompoents>
        <antd.Button type="primary" onClick={() => updateMsg('更新组件props')}>
          更新组件文案
        </antd.Button>
      </div>
    )
  }
  ReactDOM.render(<AntdDemo />, document.querySelector('#antddemo'))
</script>

更多的坑

到这一步,其实我的项目需求也写完了,毕竟老项目只是显示一下图表之类的,没有用到太多新颖的功能。那会不会还有更多的坑?应该是有的~等着自己探索和解决了

最后

感慨一下:旧项目能用新技术去写也是很幸福的一件事了,省去了 JQ 一个个 div 找到在赋值

另外一个博客地址。有空多多支持:Jioho/blog


本文链接: http://www.dtmao.cc/news_show_550051.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?