利用React/anu編寫一個彈出層

本文將一步步介紹如何使用React或anu建立 一個彈出層。javascript

React時代,代碼都是要通過編譯的,咱們不少時間都耗在babel與webpack上。所以本文也介紹如何玩webpack與babel。html

咱們建立一個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。java

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

anu自己沒有propTypes,而react最近的版本也把propTypes拆了出來,所以咱們須要獨立安裝prop-types這個包。node

webpack咱們緊隨時髦,使用2.0, 而babel則是一大堆東西。react

而後咱們在控制檯npm install敲一下,會給咱們安裝上幾屏的依賴,下面只是展現了一部分。可見前端的發展多麼可怕,之前只是幾個JS文件就以爲很是臃腫了,如今幾百個習覺得常。儘管它們大部分是預處理JS的。這也爲React帶來巨大的門檻,門檻越高,工資越高。




webpack

而後 ui目錄下創建一個src目錄,裏面建toast.js。git

//第一部分,引入依賴與定義模塊內的全局變量
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裏,沒法剝離,纔出現這奇葩的狀況。github

而後 咱們再建一個app.js,裏面模擬業務線的同窗使用toast吧。web

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-width: 1rem;
            max-width: 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分離出來,最後可恥的失敗了,誰會麻煩給個參考項目給我。

相關文章
相關標籤/搜索