前端星計劃之高複用的組件的設計

前言

感受此次去北京參加的前端星計劃,收穫很是的大,特別是月影大大講的js課程,讓我感受再次以前根本就沒有學到js的精髓,一直都是在爲了完成某個頁面而去寫這個頁面,根本沒有去考慮這個頁面接下來的維護,全部的變量所有都耦合在一塊兒,爲了改一個點,你須要該無數地方的代碼。而後在更多的時候都是在寫重複的代碼,根本沒有考慮到組件的複用的問題。而後對es6不少新的方法都沒有接觸過。總而言之,就是本身太菜了,還要加把勁的學習。css

輪播圖組件實現大概思想

輪播組件之結構設計

在編寫一個組件的時候你先須要把組件的樣式給寫出來,好比說,咱們要作一個輪播的組件,而後就是幾張圖片疊加在一塊兒,須要哪張圖片就顯示哪張圖片,這個是基礎的樣式。html

  1. 圖片結構是一個列表型結構,因此主體用
  2. 使用 css 絕對定位將圖片重疊在同一個位置
  3. 輪播圖切換的狀態使用修飾符(modifier)
  4. 輪播圖的切換動畫使用 css transition前端

    輪播組件之API設計

    在你想好要作組件以前,你須要對這個組件進行api的設置。建一個類,而後在類中寫各類須要的方法。
    imagees6

    輪播組件之控制流設計

    在類之中的方法之間仍是會有必定的耦合,這樣的話能夠採用自定義事件的方法,只須要綁定事件就能夠web

控制結構小程序

<a class="slide-list__next"></a>
<a class="slide-list__previous"></a>
<div class="slide-list__control">
    <span class="slide-list__control-buttons--selected"></span>
    <span class="slide-list__control-buttons"></span>
    <span class="slide-list__control-buttons"></span>
    <span class="slide-list__control-buttons"></span>
</div>

自定義事件api

const detail = {index: idx}
const event = new CustomEvent('slide', {bubbles:true, detail})
this.container.dispatchEvent(event)

輪播圖之各類優化

在完成上面的後你還能夠進行各類優化,好比說,依賴注入,把每個小插件做爲一個依賴注入到組件中,須要這個依賴就注入一下就好,不須要就不要管他。代碼也不會報錯。而後你還能夠進行插件化和模版化把每一個依賴的小插件的html代碼寫在js中,只有使用了這個插件纔會渲染這段代碼。dom

拖動條組件的設計

樣式設計

大概寫出來是這個樣子,左邊是輸入框,經過輸入框輸入能夠改變右邊的進度,而後右邊是能夠拖動的拖動條,拖動後能夠改變左邊的輸入框的值。ide

image

API設計

這個組件大概包括如下的幾個接口函數

image.png

實現思路

因爲須要數據雙向綁定,這裏使用的方法是,在你改變數據的時候不是直接改變數據,而是調用setData方法來改變數據,調用setData方法裏面會調用數據的渲染方法,就和小程序同樣,這樣改變數據纔會激活視圖的更新。

而後clickDot是實現點擊小圓點來拖動的效果。對小圓點設置一個mousedown事件,發生按下去的事件後對窗口設置一個mousemove事件隨時改變小圓點的位置,當鬆開的時候就清楚mousemove事件。

同時在小圓點動的時候激活一個自定義的移動事件,爲了響應的更改input中的數據。

改變進度和小圓點的位置的時候,所有依賴的是定義的數據,因此渲染界面只須要setData一下就能夠了。

而後對於輸入框,若是界面改變了,就會激活自定義事件,監聽一下,而後經過getPercentage來得到當前的數據。若是輸入框裏面的值變了,而後調用setData方法就行了。

總結反思

這是第一次使用類的方式來寫組件,基本實現了數據的雙向綁定,而後在new的時候你能夠配置一些基本的參數,而後還學會了自定義事件,在此以前是經過回調函數來實現的。可是仍是有許多須要改進的地方,組件還能夠細分紅幾個小的插件,在新建的時候就能夠經過依賴注入的方式來注入想要的插件

代碼

html
<div id="control">
    <div class="sensitivity" id="sensitivity">
        <div class="line" id="line">
            <div class="progress" id="progress"></div>
        </div>
        <div class="dot"></div>
    </div>
</div>
css
*{
    margin: 0;
    padding: 0;
}
.sensitivity {
    width: 100px;
    position: relative;
}
.line {
    width: 100%;
    height: 2px;
    background-color: #cccccc;
    border-radius: 1px;
    overflow: hidden;
}
.progress {
    height: 2px;
    width: 0;
    background-color: #57A3F3;
    -webkit-transition: all .2s;
    -moz-transition: all .2s;
    -ms-transition: all .2s;
    -o-transition: all .2s;
    transition: all .2s;
}
.dot {
    cursor: pointer;
    height: 6px;
    width: 6px;
    border: 2px solid #57A3F3;
    box-sizing: border-box;
    background-color: #ffffff;
    border-radius: 50%;
    position: absolute;
    top: -2px;
    left:  -3px;
    -webkit-transition: all .2s;
    -moz-transition: all .2s;
    -ms-transition: all .2s;
    -o-transition: all .2s;
    transition: all .2s;
}

.dot:hover {
    cursor: pointer;
    border: 1px solid #57A3F3;
}
js-滑動類
class Slide {
    constructor(dot, progress, father) {
        this.data = 0;
        //判斷是否存在
        this.dot = dot;
        this.progress = progress;
        //父組件
        this.father = father;
    }
    //設置數據
    setData(data) {
        this.data = data;
        this.setPercentage()
    }
    //渲染方法
    render() {
        this.clickDot();
    }
    //全部監聽事件來控制拖動條
    clickDot() {
        let sensitivity = this.father.querySelector(".sensitivity");
        let dot = this.father.querySelector(".sensitivity .dot");
        //自定義事件,經過監聽事件來從新渲染dom
        const slideEvent = new CustomEvent("slide");

        dot.addEventListener("mousedown", (e) => {
            document.onmousemove = (e) => {
                //設置data
                this.setData((e.clientX - sensitivity.offsetLeft) / sensitivity.offsetWidth * 100);
                document.dispatchEvent(slideEvent);
            };
            document.onmouseup = () => {
                document.onmousemove = null;
            }
        });
    }
    //設置百分數來改變進度
    setPercentage() {
        if (this.data < 0) {
            this.data = 0;
        }
        if (this.data > 100) {
            this.data = 100;
        }
        let sensitivityWidth = this.father.querySelector(".sensitivity").offsetWidth;

        if (this.dot) {
            this.setDot(this.data * sensitivityWidth * 0.01 - 3 + 'px');
        }
        if (this.progress) {
            this.setProgress(this.data * sensitivityWidth * 0.01 + "px");
        }
    }
    //獲得當前的百分數
    getPercentage() {
        return this.data;
    }
    //設置點的位置
    setDot(position) {
        let dot = this.father.querySelector(".sensitivity .dot");
        if (dot) {
            dot.style.left = position;
        }
    }
    //設置進度的位置
    setProgress(position) {
        let progress = this.father.querySelector(".sensitivity .progress");
        if (progress) {
            progress.style.width = position;
        }
    }
}
js-new
let father = document.querySelector("#control");
    let a = new Slide(true, true, father);
    a.render();

    document.addEventListener("slide", (e) => {
        document.querySelector("#input").value = parseInt(a.getPercentage());
    });
    //監聽輸入框改變
    document.querySelector("#input").onkeyup = () => {
        a.setData(document.querySelector("#input").value)
    }
相關文章
相關標籤/搜索