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操作一起寫,但是完成了組件化。

下一篇我們就組件化與複用進行優化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章