Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Einführung in Front-End-Responsive-Programmierlösungen und deren Mängel (mit Code)

Detaillierte Einführung in Front-End-Responsive-Programmierlösungen und deren Mängel (mit Code)

不言
不言Original
2018-08-14 15:14:452504Durchsuche

Dieser Artikel bietet Ihnen eine detaillierte Einführung in die Front-End-Responsive-Programmierung und ihre Mängel (mit Code). Ich hoffe, dass er für Sie hilfreich ist. helfen.

Viele Dinge in der realen Welt funktionieren responsiv. Wir werden beispielsweise Fragen von anderen entgegennehmen und dann antworten und entsprechende Antworten geben. Während des Entwicklungsprozesses habe ich auch viel Responsive Design angewendet und einige Erfahrungen gesammelt, in der Hoffnung, andere zu inspirieren.

Der Hauptunterschied zwischen reaktiver Programmierung und gewöhnlicher Programmierung besteht darin, dass die reaktive Programmierung im Push-Modus funktioniert, während die nicht-reaktive Programmierung im Pull-Modus funktioniert. Ereignisse sind zum Beispiel eine sehr häufige reaktive Programmierung:

button.on('click', () => {  
    // ...})

Auf nicht-reaktive Weise wird es so aussehen:

while (true) {  
    if (button.clicked) {        // ...
    }
}

Natürlich, egal ob in Bezug auf In Bezug auf Code-Eleganz und Ausführungseffizienz sind nicht-responsive Methoden nicht so gut wie responsive Designs.

Event Emitter

Event Emitter ist eine Event-Implementierung, mit der die meisten Menschen vertraut sind. Sie ist sehr einfach und praktisch. Wir können Event Emitter verwenden, um einfaches Responsivitätsdesign zu implementieren B. die folgende asynchrone Suche:

class Input extends Component {  
    state = {        value: ''
    }
    onChange = e => {        this.props.events.emit('onChange', e.target.value)
    }
    afterChange = value => {        this.setState({
            value
        })
    }
    componentDidMount() {        this.props.events.on('onChange', this.afterChange)
    }
    componentWillUnmount() {        this.props.events.off('onChange', this.afterChange)
    }
    render() {        
    const { value } = this.state        
    return (            <input value={value} onChange={this.onChange} />
        )
    }
}
class Search extends Component {  
    doSearch = (value) => {
        ajax(/* ... */).then(list => this.setState({
            list
        }))
    }
    componentDidMount() {
        this.props.events.on(&#39;onChange&#39;, this.doSearch)
    }
    componentWillUnmount() {
        this.props.events.off(&#39;onChange&#39;, this.doSearch)
    }
    render() {
        const { list } = this.state
        return (            <ul>
                {list.map(item => <li key={item.id}>{item.value}</li>)}            </ul>
        )
    }
}

Hier werden wir feststellen, dass die Implementierung von Event Emitter viele Mängel aufweist und wir Ressourcen in ComponentWillUnmount manuell freigeben müssen. Seine Ausdruckskraft reicht beispielsweise nicht aus, wenn wir bei der Suche mehrere Datenquellen aggregieren müssen:

class Search extends Component {  
    foo = &#39;&#39;
    bar = &#39;&#39;
    doSearch = () => {
        ajax({
            foo,
            bar
        }).then(list => this.setState({
            list
        }))
    }
    fooChange = value => {        this.foo = value        this.doSearch()
    }
    barChange = value => {        this.bar = value        this.doSearch()
    }
    componentDidMount() {        this.props.events.on(&#39;fooChange&#39;, this.fooChange)        this.props.events.on(&#39;barChange&#39;, this.barChange)
    }
    componentWillUnmount() {        this.props.events.off(&#39;fooChange&#39;, this.fooChange)        this.props.events.off(&#39;barChange&#39;, this.barChange)
    }
    render() {        // ...
    }
}

Offensichtlich ist die Entwicklungseffizienz sehr gering.

Redux

Redux verwendet einen Ereignisstrom, um Reaktivität zu implementieren. Da der Reduzierer eine reine Funktion sein muss, ist die einzige Möglichkeit, Reaktivität zu implementieren oder in Middleware.

Wenn Sie den Store abonnieren, kann Redux nur Dirty Checking verwenden, da es nicht genau ermitteln kann, welche Daten sich geändert haben. Zum Beispiel:

function createWatcher(mapState, callback) {  
    let previousValue = null
    return (store) => {
        store.subscribe(() => {            const value = mapState(store.getState())            if (value !== previousValue) {
                callback(value)
            }
            previousValue = value
        })
    }
}const watcher = createWatcher(state => {  
    // ...}, () => {    // ...})

watcher(store)

Diese Methode hat zwei Nachteile: Zum einen treten Effizienzprobleme auf, wenn die Daten komplex und die Datenmenge relativ groß ist ; Ja, es wäre schwierig, wenn die Funktion „mapState“ auf dem Kontext basieren würde. In React-Redux ist der zweite Parameter von MapStateToProps in der Connect-Funktion Props, die über die obere Komponente übergeben werden können, um den erforderlichen Kontext zu erhalten. Auf diese Weise wird der Listener jedoch zu einer React-Komponente und wird so gemountet, wie die Komponente Und das Entladen wird erstellt und zerstört. Wenn wir möchten, dass diese Reaktionsfähigkeit unabhängig von Komponenten ist, wird es ein Problem geben.

Eine andere Möglichkeit besteht darin, Datenänderungen in der Middleware zu überwachen. Dank des Redux-Designs können wir die entsprechenden Datenänderungen erhalten, indem wir bestimmte Ereignisse (Aktionen) abhören.

const search = () => (dispatch, getState) => {  
    // ...}const middleware = ({ dispatch }) => next => action => {  
    switch action.type {        case &#39;FOO_CHANGE&#39;:        case &#39;BAR_CHANGE&#39;: {            const nextState = next(action)            // 在本次dispatch完成以后再去进行新的dispatch
            setTimeout(() => dispatch(search()), 0)            return nextState
        }        default:            return next(action)
    }
}

Diese Methode kann die meisten Probleme lösen, aber in Redux abonnieren Middleware und Reduzierer tatsächlich implizit alle Ereignisse (Aktion), was offensichtlich unvernünftig ist, obwohl es keine Leistung gibt Unter der Prämisse der Frage ist es vollkommen akzeptabel .

Objektorientierte Reaktionsfähigkeit

ECMASCRIPT 5.1 führt Getter und Setter ein, und wir können eine Reaktionsfähigkeit durch Getter und Setter implementieren.

class Model {  
    _foo = &#39;&#39;
    get foo() {        return this._foo
    }
    set foo(value) {        this._foo = value        this.search()
    }
    search() {        // ...
    }
}// 当然如果没有getter和setter的话也可以通过这种方式实现class Model {  
    foo = &#39;&#39;
    getFoo() {        return this.foo
    }
    setFoo(value) {        this.foo = value        this.search()
    }
    search() {        // ...
    }
}

Mobx und Vue verwenden diese Methode, um Reaktionsfähigkeit zu implementieren. Natürlich können wir Proxy auch verwenden, wenn die Kompatibilität nicht berücksichtigt wird.

Wenn wir auf mehrere Werte reagieren und dann einen neuen Wert erhalten müssen, können wir dies in Mobx tun:

class Model {  
    @observable hour = &#39;00&#39;
    @observable minute = &#39;00&#39;
    @computed get time() {        return `${this.hour}:${this.minute}`
    }
}

Mobx sammelt zur Laufzeit die Werte, von denen die Zeit abhängt , und verwenden Sie diese Die Neuberechnung des Zeitwerts, wenn sich der Wert ändert (Auslösen des Setters), ist offensichtlich viel bequemer und effizienter als die EventEmitter-Methode und intuitiver als die Redux-Middleware.

Hier gibt es jedoch auch einen Nachteil. Das auf dem Getter basierende berechnete Attribut kann jedoch in vielen Fällen nur die Situation von y = f(x) beschreiben werde y = warte auf f( x), Getter kann diese Situation nicht beschreiben.

In dieser Situation können wir die von Mobx bereitgestellte Autorun-Funktion verwenden, um Folgendes zu erreichen:

class Model {  
    @observable keyword = &#39;&#39;
    @observable searchResult = []    constructor() {
        autorun(() => {            // ajax ...
        })
    }
}

Da der Erfassungsprozess von Laufzeitabhängigkeiten vollständig implizit ist, tritt hier häufig ein Problem bei der Erfassung unerwarteter Abhängigkeiten auf:

class Model {  
    @observable loading = false
    @observable keyword = &#39;&#39;
    @observable searchResult = []    constructor() {
        autorun(() => {            if (this.loading) {                return
            }            // ajax ...
        })
    }
}

Offensichtlich sollte das Laden hier nicht durch den gesuchten Autorun erfasst werden. Um dieses Problem zu lösen, wird etwas zusätzlicher Code hinzugefügt, und der zusätzliche Code birgt leicht die Möglichkeit für Fehler. Alternativ können wir die erforderlichen Felder auch manuell angeben, aber diese Methode erfordert einige zusätzliche Vorgänge:

class Model {  
    @observable loading = false
    @observable keyword = &#39;&#39;
    @observable searchResult = []
    disposers = []
    fetch = () => {        // ...
    }
    dispose() {        this.disposers.forEach(disposer => disposer())
    }    constructor() {        this.disposers.push(
            observe(this, &#39;loading&#39;, this.fetch),
            observe(this, &#39;keyword&#39;, this.fetch)
        )
    }
}class FooComponent extends Component {  
    this.mode = new Model()
    componentWillUnmount() {        this.state.model.dispose()
    }    // ...}

Und wenn wir die Zeitleiste beschreiben müssen, ist Mobx etwas unzureichend. Beispielsweise müssen Sie die Suche verzögern 5 Sekunden.

Verwandte Empfehlungen:

Puzzle-responsive Front-End-Framework-Version des responsiven Backends offiziell veröffentlicht_html/css_WEB-ITnose

Verwendung ein sehr einfaches responsives Front-End-Entwicklungsframework_html/css_WEB-ITnose


Das obige ist der detaillierte Inhalt vonDetaillierte Einführung in Front-End-Responsive-Programmierlösungen und deren Mängel (mit Code). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn