乐趣区

React实战为什么需要组件化1

为什么需要组件化?

1.web 的发展因为 HTML CSS Javascript 分工造成了协作,所以需要标准和接口,所以需要组件化。

2. 追求效率,重复使用。

怎么实现复用?

我们总不能把同事的代码拷贝过来,拷贝 css,拷贝 js,最后改里面文字。这样也忒费劲了,而且不可持续化。接下来我们就说下怎么组件化。我们先不用 react。先说原生。

为什么说原生。

1. 简单。

2. 我们能够从原生 js 中真的会用 react 组件化,不懂原理只会 react 组件化语法,遇到实际项目也棘手。

1. 我们遇到这么一个实际问题。

你同事写了一个星星评分,你想复用,原始代码如下,怎么办?我们这里简化一下,说五个星星部分。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title> 星星评分 </title>
    <style type="text/css">
        .starbox span {
            width: 27px;
            height: 28px;
            display: inline-block;
            background: url(images/star.gif) no-repeat 0px 0px;
            cursor: pointer;
            float: left;
        }

        .starbox strong {
            float: left;
            padding-top: 6px;
            padding-left: 10px;
        }
        .starbox .on {background-position: 0px -29px;}
    </style>
    <script>
        window.onload = function(){var aStar = document.querySelectorAll('.starbox span');
            var oS = document.querySelector('.starbox .score');
            for(let i =0;i<aStar.length;i++){aStar[i].onclick = function(){for(let j =0;j<aStar.length;j++){aStar[j].className = '';
                    }
                    for(let j =0;j<=i;j++){aStar[j].className = 'on'; 
                    }
                    oS.innerHTML = (i+1)+'分';
                };
            }
        };
    </script>
</head>
<body>
    <div class='starbox'>
        <span data-index="0"></span>
        <span data-index="1"></span>
        <span data-index="2"></span>
        <span data-index="3"></span>
        <span data-index="4"></span>
        <strong class='score'>0 分 </strong>
    </div>
</body>
</html>

2. 组件化结构

我们先让这个组件能够显示我们的 html 结构跟样式。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .starbox span {
            width: 27px;
            height: 28px;
            display: inline-block;
            background: url(images/star.gif) no-repeat 0px 0px;
            cursor: pointer;
            float: left;
        }

        .starbox strong {
            float: left;
            padding-top: 6px;
            padding-left: 10px;
        }

        .starbox .on {background-position: 0px -29px;}
    </style>
    <script>
        window.onload = function () {
            //2. 但是没有,所以我们搞一个 Class
            class RatingStar {
                //  render 专门用来决定显示什么东西的
                render() {
                    return `
                        <div class='starbox'>
                            <span data-index="0"></span>
                            <span data-index="1"></span>
                            <span data-index="2"></span>
                            <span data-index="3"></span>
                            <span data-index="4"></span>
                            <strong class='score'>0 分 </strong>
                        </div>
                    `;
                }
            }
            var oBox = document.getElementById('box');
            //1. 假设有一个 Class RatingStar  它就是一个组件,包含所有组件信息
            var oStar = new RatingStar();
            oBox.innerHTML = oStar.render();};
    </script>
</head>

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

</html>

我们先按照注释思路走,但是有个问题:事件不好用。

return `
    <div class='starbox'>
        <span data-index="0"></span>
        <span data-index="1"></span>
        <span data-index="2"></span>
        <span data-index="3"></span>
        <span data-index="4"></span>
        <strong class='score'>0 分 </strong>
    </div>
`;

因为上面是 return 的字符串不好加事件,我们直接在外面包一层 div,再添加事件。

3. 添加事件

外面包一个 div。

// 创建一个元素
const createDOMFromString = (domString) => {const div = document.createElement('div')
  div.innerHTML = domString
  return div
}

我们现在到原来的例子里面加事件。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .starbox span {
            width: 27px;
            height: 28px;
            display: inline-block;
            background: url(images/star.gif) no-repeat 0px 0px;
            cursor: pointer;
            float: left;
        }
        .starbox strong {
            float: left;
            padding-top: 6px;
            padding-left: 10px;
        }
        .starbox .on {background-position: 0px -29px;}
    </style>
    <script>
        window.onload = function () {const createDOMFromString = (domString) => {const div = document.createElement('div')
                div.innerHTML = domString
                return div;
            }
            class RatingStar {
                //  render 专门用来决定显示什么东西的
                render() {
                    this.el = createDOMFromString(`
                        <div class='starbox'>
                            <span data-index="0"></span>
                            <span data-index="1"></span>
                            <span data-index="2"></span>
                            <span data-index="3"></span>
                            <span data-index="4"></span>
                            <strong class='score'>0 分 </strong>
                        </div>
                    `);
                    this.el.addEventListener('click', ()=>{console.log(this);
                    }, false);
                    return this.el;
                }
            }
            var oBox = document.getElementById('box');
            var oStar = new RatingStar();
            oBox.appendChild(oStar.render());
        };
    </script>
</head>
<body>
    <div id="box">
    </div>
</body>

</html>

重点是加事件

this.el.addEventListener('click', ()=>{console.log(this);
}, false)

4. 添加数据与逻辑

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .starbox span {
            float: left;
            width: 27px;
            height: 28px;
            display: inline-block;
            background: url(images/star.gif) no-repeat 0px 0px;
            cursor: pointer;
        }
        .starbox strong {
            float: left;
            padding-top: 6px;
            padding-left: 10px;
        }
        .starbox .on {background-position: 0px -29px;}
    </style>
    <script>
        window.onload = function () {const createDOMFromString = (domString) => {const div = document.createElement('div')
                div.innerHTML = domString
                return div;
            }
            class RatingStar {constructor() {this.state = { score: 0}
                }
                changeScore(ev) {const aStar = document.querySelectorAll('.starbox span');
                    const oS = document.querySelector('.starbox .score');

                    this.state.score = Number(ev.target.dataset.index) + 1;
                    for (let i = 0; i < aStar.length; i++) {aStar[i].className = '';
                    }
                    for (let i = 0; i <= Number(ev.target.dataset.index); i++) {aStar[i].className = 'on';
                    }
                    oS.innerHTML = this.state.score + '分';
                }
                //  render 专门用来决定显示什么东西的
                render() {
                    this.el = createDOMFromString(`
                        <div class='starbox'>
                            <span data-index="0"></span>
                            <span data-index="1"></span>
                            <span data-index="2"></span>
                            <span data-index="3"></span>
                            <span data-index="4"></span>
                            <strong class='score'>0 分 </strong>
                        </div>
                    `);
                    this.el.addEventListener('click', this.changeScore.bind(this), false);
                    return this.el;
                }
            }
            var oBox = document.getElementById('box');
            var oStar = new RatingStar();
            oBox.appendChild(oStar.render());
        };
    </script>
</head>

<body>
    <div id="box">

    </div>
</body>

</html>

注意,请不要陷入细节:

this.el.addEventListener('click', this.changeScore.bind(this), false);

先注意明白这里调用了 changeScore 就行了,先别考虑什么矫正 this,或者事件对象什么的,我们先了解 react 原理。

这里修改 DOM 方法很暴力,react 是用 virtualDOM 和 diff 算法优化了这块,现在我们实现了组件化。

总结:

1. 我们从实际问题出发,用 class 封装了一个初始的类。

2. 添加事件;

3. 我们在事件里面加了具体逻辑,虽然数据和 DOM 操作一起写,但是完成了组件化。

下一篇我们就组件化与复用进行优化。

退出移动版