• 利用React/anu编写一个弹出层


    本文将一步步介绍如何使用React或anu创建 一个弹出层。

    React时代,代码都是要经过编译的,我们很多时间都耗在babel与webpack上。因此本文也介绍如何玩webpack与babel。

    我们创建一个ui目录,里面添加一个package.json。内容如下,里面已经是尽量减少babel插件的使用了。

    {
      "name": "ui",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo "Error: no test specified" && exit 1"
      },
      "author": "RubyLouvre",
      "license": "ISC",
      "devDependencies": {
       
        "babel-core": "^6.24.1",
        "babel-loader": "^6.4.1",
        "babel-preset-es2015": "^6.24.1",
        "babel-preset-react": "^6.16.0",
    
        "webpack": "^2.2.1"
      },
      "dependencies": {
        "prop-types": "^15.5.10",
        "anujs": "^1.0.0"
      }
    }

    如果你不想用anu,可以改成react与react-dom。

      "dependencies": {
        "prop-types": "^15.5.10"
        "react": "^15.5.4",
        "react-dom": "^15.5.4"
      }

    anu本身没有propTypes,而react最近的版本也把propTypes拆了出来,因此我们需要独立安装prop-types这个包。

    webpack我们紧随时髦,使用2.0, 而babel则是一大堆东西。

    然后我们在控制台npm install敲一下,会给我们安装上几屏的依赖,下面只是展示了一部分。可见前端的发展多么可怕,以前只是几个JS文件就觉得非常臃肿了,现在几百个习以为常。尽管它们大部分是预处理JS的。这也为React带来巨大的门槛,门槛越高,工资越高。




    然后 ui目录下建立一个src目录,里面建toast.js。

    
    //第一部分,引入依赖与定义模块内的全局变量
    import React,{Component} from 'react';
    import PropTypes from 'prop-types';
    import ReactDOM from 'react-dom';
    
    let singleton = null;
    const container = document.createElement('div'),
    
        defaultProps = {
            show: false
        },
    
        propTypes = {
            /**
             * @property show
             * @description 是否显示,默认false
             * @type Boolean
             * @default false
             * @skip
             */
            show: PropTypes.bool
        };
    
    document.body.appendChild(container);
    
    //第二部分,定义组件
    class ToastReact extends Component {
        constructor(props) {
            super(props);
            this.state = {
                show: this.props.show,
                content: '',
                autoHideTime: 2000
            };
            this._timer = null;
            singleton = this;
        }
    
        shouldComponentUpdate(nextProps, nextState) {
            this.setState({ show: nextState.show });
            if (!!this._timer) {
                clearTimeout(this._timer);
                this._timer = null;
            }
    
            this._timer = setTimeout(() => this.setState({ show: false }), nextState.autoHideTime);
            return true;
        }
    
        componentWillUnmount() {
            clearTimeout(this._timer);
            document.body.removeChild(container);
        }
    
        render() {
            const { show, content } = this.state;
            return (
                <div
                    className="yo-toast"
                    style={{
                        display: show ? null : 'none'
                    }}
                >{content}</div>
            );
        }
    }
    
    ToastReact.propTypes = propTypes;
    ToastReact.defaultProps = defaultProps;
    
    ReactDOM.render(<ToastReact />, container);
    // 第三部分,一个代理对象,设置Toast的显示隐藏函数
    /**
     * Toast显隐函数
     * @returns {Object}
     */
    export default {
        /**
         * @method show
         * @type Function
         * @description 打开组件,显示传入的内容
         * @param {String} content 组件显示的内容
         * @param {Number} [autoHideTime] 内容显示的持续时间,默认2000ms
         */
        show(content = 'no content', autoHideTime = 2000) {
            singleton.setState({
                content,
                autoHideTime,
                show: true
            });
            return this;
        },
        /**
         * @method hide
         * @type Function
         * @description 关闭正在显示的组件
         */
        hide() {
            singleton.setState({ show: false });
            return this;
        }
    };

    整个文件分三部分,大家认真看注释。之所以将弹层变成单例模式,因此窗口通常只存在一个弹层。存在多个弹层的情况,大多数是设计不合理吧,比如说层上层。这种由于在React时代,数据都保存在redux中,因此当层上层出现时,原弹层的用法输入可以保存到redux中,然后再改变弹层的内容,就可以实现层上层的功能了。在jQuery时代,数据固化在dom里,无法剥离,才出现这奇葩的情况。

    然后 我们再建一个app.js,里面模拟业务线的同学使用toast吧。

    
    import Tooltip from './coast';
    
    var btn = document.querySelectorAll('.demo');
    
    btn[0].addEventListener('click', function() {
        console.log('tooltip');
        Tooltip.show('the tooltip autoHide after 2s');
    }, false);
    
    btn[1].addEventListener('click', function() {
        console.log('tooltip 2')
        Tooltip.show('the tooltip autoHide after 3s', 3000);
    }, false);
    
    btn[2].addEventListener('click', function() {
        console.log('tooltip 3')
        var tip = Tooltip.show('the tooltip will be hidden before the default time 2s');
        setTimeout(()=>tip.hide(), 1000);
    }, false);

    然后在src的上一级目录,即我们原来ui 目录建一个index.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>tooltip demo</title>
        <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
        <style>
            .yo-toast {
                position: fixed;
                top: 50%;
                left: 50%;
                -webkit-transform: translate(-50%, -50%);
                transform: translate(-50%, -50%);
                min- 1rem;
                max- 90%;
                z-index: 1500;
                height: 3rem;
                padding: 20px 10px;
                border-radius: .05rem;
                background-color: rgba(0, 0, 0, .5);
                color: #fff;
            }
        </style>
    </head>
    
    <body>
        <button>normal tooltip</button>
        <button>autohideTime tooltip</button>
        <button>hide() tooltip</button>
    
    </body>
    
    </html>

    我们准备在这个文件里引用我们的JS。JS必须要打包过的,babel处理过的。因此下面是重头戏,建立一个webpack.config.js

    const webpack = require("webpack");
    const path = require("path");
    const fs = require("fs");
    
    module.exports = {
      context: __dirname,
      entry: {
        app: "./src/app.js"
      },
      output: {
        path: __dirname + "/dist/",
        filename: "[name].js"
      },
      module: {
        rules: [
          {
            test: /.jsx?$/,
            loader: "babel-loader",
            options: {
              presets: ["es2015", "react"]
            },
            exclude: path.resolve(__dirname, "node_modules")
          }
        ]
      },
      resolve: {
        //如果不使用anu,就可以把这里注释掉
        alias: {
          react: "anujs/dist/React.js",
          react: "anujs/dist/React.js",
          "react-dom": "anujs/dist/React.js"
        }
      }
    };
    

    我们需要在resolve配置项上设置别名,anu一个JS文件就包含了react与react-dom的功能,体积又少,最适合线上使用。

    我们敲下webpack命令,就发生成一个dist/app.js文件,然后 在index.html上引用它

      <script src="./dist/app.js"></script>

    最终效果图

    本来还想把业务中用到的babel helpers分离出来,最后可耻的失败了,谁会麻烦给个参考项目给我。

  • 相关阅读:
    2.3 节的练习
    2.2 节的练习--Compiler principles, technologys, &tools
    web测试点整理(二) -- 输入框
    web测试点整理 -- 注册/登录
    产品测试的思路
    C语言学习--静态链接库和动态链接库
    C语言学习(四)--操作符
    C语言学习(三)--语句
    C语言学习(二)--数据类型
    C语言学习(一)--基本概念
  • 原文地址:https://www.cnblogs.com/libin-1/p/6964555.html
Copyright © 2020-2023  润新知