lxc-前端知識整理

轉載於前端知識整理2

1.ES6 語法

1.ES6 模塊化如何使用,開發環境如何打包?
語法: import export (注意有無 default 的區別)
環境: babel 編譯 ES6 語法,模塊化可用 webpack 和 rollup
擴展: 說一下本身對模塊化標準統一的期待
rollup 功能單一(只作模塊化的打包編譯),webpack 功能強大css

2.Class 和普通構造函數有何區別?
(1)Class 在語法上更加貼合面向對象的寫法
(2)Class 實現繼承更加易讀、易理解
(3)更易於寫 Java 等後端語言的使用
(4)本質仍是語法糖,使用 prototypehtml

class MathHandle {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    add() {
        return this.x + this.y;
    }
}
const m = new MathHandle(1, 2);
console.log(m.add()); // 3
console.log(typeof MathHandle); // 'function'
console.log(MathHandle.prototype.constructor === MathHandle); // true
console.log(m.__proto__ === MathHandle.prototype); // true

2.原型的實際應用、原型擴展

1.說一個原型的實際應用?
(1)描述一下 jquery 如何使用原型
(2)描述一下 zepto 如何使用原型
(3)再結合本身的項目經驗,說一個本身開發的例子前端

2.原型如何體現它的擴展性?
(1)說一下 jquery 和 zepto 的插件機制
(2)結合本身的開發經驗,作過的基於原型的插件vue

my-jquery.jsnode

(function(window) {
    let jQuery = function (selector) {
        return new jQuery.fn.init(selector);
    };

    jQuery.fn = {
        css: function (key, value) {
            console.log('css'); // 這裏只是簡單打印
        },
        html : function (value) {
            return 'html';
        }
    };

    let init = jQuery.fn.init = function (selector) {
        let slice = Array.prototype.slice;
        let dom = slice.call(document.querySelectorAll(selector));
        let len = dom ? dom.length : 0;
        for (let i = 0; i < len; i++) {
            this[i] = dom[i];
        }
        this.length = len;
        this.selector = selector;
    };

    init.prototype = jQuery.fn;
    window.$ = jQuery;
})(window);

使用示例:jquery

<script src="my-jquery.js"></script>
<script>
    // 插件擴展
    $.fn.getNodeName = function () {
        return this[0].nodeName;
    }
</script>
<script>
    let $p = $('p'); // jquery 實例
    $p.css('font-size', '16px'); // css 是原型方法
    console.log($p.html()); // html 是原型方法
    console.log($p.getNodeName()); // getNodeName 是本身擴展的方法
    
    let $div1 = $('#div1'); // jquery 實例
    $div1.css('color', '#f00'); // css 是原型方法
    console.log($div1.html()); // html 是原型方法
    console.log($div1.getNodeName()); // getNodeName 是本身擴展的方法
</script>

3.異步

1.什麼是單線程,和異步有什麼關係?
(1)單線程 - 只有一個線程,同一時間只能作一件事情,兩段JS不能同時執行
(2)緣由 - 避免DOM渲染的衝突:
瀏覽器須要渲染DOM
JS能夠修改DOM結構
JS執行的時候,瀏覽器DOM渲染會暫停
兩段JS也不能同時執行(都修改DOM就衝突了)
webworker 支持多線程,可是不能訪問DOM
(3)解決方案 - 異步
問題1:沒按照書寫方式執行,可讀性差
問題2:callback中不容易模塊化linux

2.什麼是event-loop?
(1)事件輪詢,JS實現異步的具體解決方案
(2)同步代碼,直接執行
(3)異步函數先放在 異步隊列 中
setTimeout 沒有延時,馬上放入異步隊列
setTimeout 有延時,延時事後放入異步隊列
ajax,待ajax加載完成後放入異步隊列
(4)待同步函數執行完畢,輪詢執行 異步隊列 的函數webpack

// ajax請求請求成功以後被放入異步隊列
$.ajax({
    url: './data.json',
    success: function (res) {
        console.log(res);
        console.log('a');
    }
});
// 1000ms 以後被放入異步隊列
setTimeout(function () {
    console.log('b');
}, 1000);
// 馬上被放入異步隊列
setTimeout(function () {
    console.log('c');
});
// 主進程
console.log('d');

3.是否用過jquery的Deferred?
(1)jQuery 1.5 的變化
沒法改變JS異步和單線程的本質
只能從寫法上杜絕 callback 這種形式
它是一種語法糖形式,可是解耦了代碼
很好的體現:開放封閉原則git

// jquery 1.5 版本以前的寫法:
let ajax = $.ajax({
    url: './data.json',
    success: function (res) {
        console.log('success 1');
        console.log('success 2');
        console.log('success 3');
    },
    error: function () {
        console.log('error 1');
    }
});
// jquery 1.5 版本以後的寫法:
let ajax = $.ajax('./data.json');
ajax.then(function () {
    console.log('success a');
}, function () {
    console.log('error 1');
}).then(function () {
    console.log('success b');
}, function () {
    console.log('error 2');
});

(2)jQuery Deferred,如何簡單的封裝、使用?web

// 對 Deferred 的簡單封裝
function waitHandle() {
    // 定義
    let dtd = $.Deferred();
    let wait = function (dtd) {
        let task = function () {
            console.log('執行完成');
            dtd.resolve(); // 成功
            // dtd.reject(); // 失敗
        };
        setTimeout(task, 2000);

        // wait 返回
        // 注意,這裏返回的是 promise 對象,而不是直接返回 deferred 對象
        return dtd.promise();
    };
    // 最終返回
    return wait(dtd);
}
let w = waitHandle(); // promise 對象
// w.reject(); // 報錯,w.reject is not a function
$.when(w).then(function () {
    console.log('success 1');
}, function () {
    console.log('error 1');
});
$.when(w).then(function () {
    console.log('success 2');
}, function () {
    console.log('error 2');
});

// 1.總結,dtd的API可分爲兩類,用意不一樣
// 2.第一類:dtd.resolve dtd.reject,這是主動觸發的函數
// 3.第二類:dtd.then dtd.done dtd.fail,這是被動監聽的函數
// 4.這兩類應該分開,用意不一樣,不然後果很嚴重
// 5.能夠在上面代碼建立實例以後執行 w.reject() 試一下,會報錯

(3)初步引入 Promise 概念,promise 和 Deferred 的區別?
最主要的區別就是,Deferred 對象有主動修改和被動監聽的函數,它們混在了一塊兒,容易被外部篡改。
promise 對象只能被動監聽,不能主動修改。

4.Promise 的基本使用和原理?
(1)基本語法
(2)如何捕獲異常
(3)多個串聯 - 鏈式執行的好處
(4)Promise.all 和 Promise.race
(5)Promise 標準 - 狀態變化,then函數

5.介紹一下 async/await (和Promise的區別、聯繫)
(1)基本語法
(2)使用了 Promise,並無和 Promise 衝突
(3)徹底是同步的寫法,再也沒有回調函數
(4)可是:改變不了 JS 單線程、異步的本質

6.總結一下當前JS解決異步的方案
(1)jQuery Deferred
(2)Promise
(3)async/await
(4)還有一個,Generator,能夠解決異步,可是爲何不用它:
原理比較複雜
不是異步的直接替代方式
有更好更簡潔的解決方案 async/await
koa框架 也由 Generator 轉向 async/await

4.虛擬 DOM

1.vdom 是什麼?爲什麼會存在vdom?
(1)virtual dom,虛擬DOM
(2)用JS模擬DOM結構
(3)DOM變化的對比,放在JS層來作(圖靈完備語言才能作),提升效率
(4)提升重繪性能
爲什麼會存在vdom?
(1)DOM操做是「昂貴」的,JS運行效率高
(2)儘可能減小DOM操做,而不是「推到重來」
(3)項目越複雜,影響越嚴重
(4)vdom便可解決這個問題

<!--真實的dom結構-->
<ul id="list">
    <li class="item">Item 1</li>
    <li class="item">Item 2</li>
</ul>

// 對應的 vnode 基本結構
let vnode = {
    tag: 'ul',
    attrs: {
        id: 'list'
    },
    children: [
        {
            tag: 'li',
            attrs: { className: 'item' },
            children: ['Item 1']
        },
        {
            tag: 'li',
            attrs: { className: 'item' },
            children: ['Item 2']
        },
    ]
};

2.vdom 如何應用,核心API是什麼?
如何使用?使用 snabbdom 的用法來舉例

<div id="container"></div>
<button id="btn-change">change</button>

<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-class.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-props.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-style.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-eventlisteners.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/h.js"></script>
<script>
    let snabbdom = window.snabbdom;
    // 定義 patch
    let patch = snabbdom.init([
        snabbdom_class,
        snabbdom_props,
        snabbdom_style,
        snabbdom_eventlisteners,
    ]);
    // 定義 h
    let h = snabbdom.h;

    let container = document.getElementById('container');

    // 使用h函數經過 vdom 生成 vnode
    let vnode = h('ul#list', {}, [
        h('li.item', {}, 'Item 1'),
        h('li.item', {}, 'Item 2'),
    ]);

    // 第一次渲染
    patch(container, vnode);

    document.getElementById('btn-change').addEventListener('click', function () {
        // 按鈕點擊以後,模擬數據變化,生成 newVnode
        let newVnode = h('ul#list', {}, [
            h('li.item', {}, 'Item 1'),
            h('li.item', {}, 'Item B'),
            h('li.item', {}, 'Item 3'),
        ]);
        patch(vnode, newVnode);
    });
</script>

核心API:h函數,patch函數
h('<標籤名>', {...屬性...}, [...子元素...]);
h('<標籤名>', {...屬性...});
patch(container, vnode);
patch(vnode, newVnode);

3.介紹一下diff算法
(1)什麼是 diff 算法
是linux的基礎命令,是git的基本工具
(2)去繁就簡
diff算法很是複雜,實現難度很大,源碼量很大
去繁就簡,講明白核心流程,不關心細節
大部分人都不清楚細節,可是要關心核心流程
去繁就簡以後,依然具備很大挑戰性,並不簡單
(3)vdom爲什麼要用diff算法
DOM操做是「昂貴」的,所以儘可能減小DOM操做
找出本次DOM必須更新的節點來更新,其餘的不更新
這個「找出」的過程,就須要diff算法
(4)diff算法的實現流程
patch(container, vnode) 和 patch(vnode, newVnode)
createElement() 和 updateChildren()

function createElement (vnode) {
    let tag = vnode.tag;
    let attrs = vnode.attrs || {};
    let children = vnode.children || [];
    if (tag == null) return null;

    // 建立真實 DOM 元素
    let elem = document.createElement(tag);
    // 給 elem 添加屬性
    for (let attrName in attrs) {
        if (attrs.hasOwnProperty(attrName)) {
            elem.setAttribute(attrName, attrs[attrName]);
        }
    }
    // 給 elem 添加子元素
    children.forEach(function (childVnode){
        elem.appendChild(createElement(childVnode)); // 遞歸
    });

    return elem;
}
function updateChildren(vnode, newVnode) {
    let children = vnode.children || [];
    let newChildren = newVnode.children || [];

    children.forEach(function (childVnode, index) {
        let newChildVnode = newChildren[index];
        if (childVnode.tag === newChildVnode.tag) {
            // 深層次對比,遞歸
            updateChildren(childVnode, newChildVnode);
        } else {
            // 替換
            replaceNode(childVnode, newChildVnode);
        }
    });
}

function replaceNode(vnode, newVnode) {
    let elem = vnode.elem; // 真實的dom節點
    let newElem = createElement(newVnode);
    // 替換
    
}

5.MVVM 和 vue

1.說一下使用jQuery和使用vue的區別
(1)數據和視圖的分離,解耦(開放封閉原則)
(2)以數據驅動視圖,只關心數據變化,DOM操做被封裝

使用jQuery寫一個 todo-list demo

<div>
    <input type="text" name="" id="txt-title">
    <button id="btn-submit">submit</button>
</div>
<div>
    <ul id="ul-list"></ul>
</div>

<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
    var $txtTitle = $('#txt-title');
    var $btnSubmit = $('#btn-submit');
    var $ulList = $('#ul-list');
    $btnSubmit.click(function () {
        var title = $txtTitle.val();
        if (!title) return;
        var $li = $('<li>' + title + '</li>');
        $ulList.append($li);
        $txtTitle.val('');
    });
</script>

使用vue寫一個 todo-list demo

<div id="app">
    <div>
        <input type="text" v-model="title">
        <button @click="add">submit</button>
    </div>
    <div>
        <ul>
            <li v-for="item in list">{{item}}</li>
        </ul>
    </div>
</div>
<script src="vue-2.5.13.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            title: '',
            list: []
        },
        methods: {
            add: function () {
                this.list.push(this.title);
                this.title = '';
            }
        }
    });
</script>

2.說一下對MVVM的理解
(1)MVVM - Model View ViewModel
(2)三者的聯繫,以及如何對應到各段代碼(todo-list例子)
(3)ViewModel 的理解,聯繫 View 和 Model

Vue三要素
(1)響應式:vue 如何監聽到data的每一個屬性變化?
(2)模板引擎:vue 的模板如何被解析,指令如何處理?
(3)渲染:vue 的模板如何被渲染成 html?以及渲染過程

3.vue中如何實現響應式
(1)什麼是響應式?
修改 data 屬性以後,vue馬上監聽到
data 屬性被代理到 vm 上
(2)Object.defineProperty

var vm = {};
var data = {
    name: 'lxcan',
    age: 18
};
var key;
for (key in data) {
    (function(key) {
        Object.defineProperty(vm, key, {
            get: function () {
                console.log('get', data[key]);
                return data[key];
            },
            set: function (newVal) {
                console.log('set', newVal);
                data[key] = newVal;
            }
        });
    })(key);
}

4.vue中如何解析模板
(1)模板是什麼?
本質:字符串
有邏輯,如 v-if v-for 等,嵌入了JS變量
與 html 格式很像,但有很大區別
最終還要轉換爲 html 來顯示

模板最終必須轉換成JS代碼,由於:
有邏輯(v-if v-for),必須用 JS 才能實現
轉換爲 html 渲染頁面,必須用 JS 才能實現
所以,模板最終要轉換成一個 JS 函數(render 函數)

render函數小demo

<div id="app">
    <p>{{price}}</p>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            price: 100
        }
    });

    // 手寫 render 函數
    function render() {
        with (this) {   // this 就是 vm。使用了with
            return _c(
                'div',
                {
                    attrs: { 'id': 'app' }
                },
                [
                    _c('p', [_v(_s(price))])
                ]
            )
        }
    }

    // 至關於
    function render1() {
        return vm._c(
            'div',
            {
                attrs: { 'id': 'app' }
            },
            [
                vm._c('p', [vm._v(vm._s(vm.price))])
            ]
        )
    }
</script>

(2)render 函數
根據 todo-list demo 的 render 函數:
v-model 是怎麼實現的?(雙向數據綁定)
v-on:click 是怎麼實現的?(綁定click事件)
v-for 是怎麼實現的?(執行 _l() 函數,返回數組)

function render() {
    with (this) { // this 就是 vm
        return _c(
            'div',
            {
                attrs: {"id": "app"}
            },
            [
                _c(
                    'div',
                    [
                        _c(
                            'input',
                            {
                                directives: [
                                    {
                                        name: "model",
                                        rawName: "v-model",
                                        value: (title),
                                        expression: "title"
                                    }
                                ],
                                attrs: {"type": "text"},
                                domProps: {
                                    "value": (title)
                                },
                                on: {
                                    "input": function ($event) {
                                        if ($event.target.composing) return;
                                        title = $event.target.value
                                    }
                                }
                            }
                        ),
                        _v(" "),
                        _c(
                            'button',
                            {
                                on: {
                                    "click": add
                                }
                            },
                            [_v("submit")]
                        )
                    ]
                ),
                _v(" "),
                _c(
                    'div',
                    [
                        _c(
                            'ul',
                            _l((list), function (item) {
                                return _c('li', [_v(_s(item))])
                            })
                        )
                    ]
                )
            ]
        )
    }
}

(3)render 函數與 vdom
vm._c 是什麼?render 函數返回了什麼?
vm._c 其實就至關於 snabbdom 中的 h 函數
render 函數執行以後,返回的是 vnode

vm._update = function(vnode) {
    const prevVnode = vm._vnode;
    vm._vnode = vnode;
    if (!prevVnode) {
        vm.$el = vm.__patch__(vm.$el, vnode);
    } else {
        vm.$el = vm.__patch__(prevVnode, vnode);
    }
};
function updateComponent() {
    vm._update(vm._render());  // vm._render 即 render 函數,返回了 vnode
}

updateComponent 中實現了 vdom 的 patch
頁面首次渲染執行 updateComponent
data 中每次修改屬性,執行 updateComponent

總結:
(1)模板:字符串,有邏輯,嵌入了JS變量
(2)模板必須轉換爲 JS 代碼(由於 有邏輯、要渲染html、有JS變量)
(3)render 函數是什麼樣子的(price、todo-list)
(4)render 函數執行返回 vnode
(5)updateComponent

5.vue的整個實現流程
(1)第一步:解析模板成 render 函數
with 的用法
模板中的全部信息都被 render 函數包含
模板中用到的 data 中的屬性,都變成了JS變量
模板中的 v-model v-for v-on 都變成了JS邏輯
render 函數返回 vnode

(2)第二步:響應式開始監聽
Object.defineProperty 將 data 的屬性代理到 vm 上

(3)第三步:首次渲染,顯示頁面,且綁定依賴
初次渲染,執行 updateComponent ,執行 vm.render()
執行 render 函數,會訪問到 vm.list 和 vm.title
會被響應式的 get 方法監聽到

爲什麼要監聽get,直接監聽set不行嗎?
data 中有不少屬性,有些被用到,有些可能不被用到
被用到的會走到get,不被用到的不會走到get
未走到get中的屬性,set的時候咱們也無需關心
能夠避免沒必要要的重複渲染

執行 updateComponent,會走到 vdom 的 patch 方法
patch 將 vnode 渲染成 DOM,初次渲染完成

(4)第四步:data 屬性變化,觸發 rerender
修改屬性,被響應式的set監聽到
set中執行 updateComponent(異步執行)
updateComponent 從新執行 vm._render()
生成的 vnode 和 preVnode,經過 patch 進行對比
渲染到 html 中

6.組件化和 React

1.說一下對組件化的理解?
(1)組件的封裝:封裝視圖、數據、變化邏輯(數據驅動視圖變化)
(2)組件的複用:props傳遞、複用

2.JSX語法的本質
(1)html的形式
(2)引入JS變量和表達式
(3)if...else...
(4)循環
(5)style和className
(6)事件

JSX解析

// JSX代碼
var profile = <div>
                <img src="avator.png" className="profile" />
                <h3>{[user.firstName, user.lastName].join(' ')}</h3>
              </div>;
// 解析結果
var profile = React.createElement('div', null,
    React.createElement('img', {src: 'avator.png', className: 'profile'}),
    React.createElement('h3', null, [user.firstName, user.lastName].join(' ')),
);

JSX 實際上是語法糖
開發環境會將JSX編譯成JS代碼
JSX的寫法大大下降了學習成本和編碼工做量
同時,JSX也會增長debug成本

JSX => 獨立的標準
JSX是React引入的,但不是React獨有的
React已經將它做爲一個獨立標準開放,其餘項目也可用
React.createElement 是能夠自定義修改的
標準說明:自己功能已經完備;和其餘標準兼容和擴展沒問題

3.JSX和vdom的關係
(1)分析:爲什麼須要vdom?
vdom 是 React 初次推廣開來的,結合 JSX
JSX 就是模板,最終要渲染成html,數據驅動視圖
初次渲染 + 修改 state 後的 re-render
正好符合 vdom 的應用場景

(2)React.createElement 和 h 函數,最終都返回 vnode

(3)什麼時候 patch
初次渲染 - ReactDOM.render(<App/>, container)
會觸發 patch(container, vnode)
re-render - setState
會觸發 patch(vnode, newVnode)

(4)自定義組件的解析
初始化實例,而後執行 render

// JSX代碼
// return (
//     <div>
//         <Input addTitle={this.addTitle.bind(this)}/>
//         <List data={this.state.list} />
//     </div>
// )

// 解析以後的代碼
// return React.createElement('div', null,
//     React.createElement(Input, {addTitle: this.addTitle.bind(this)}),
//     React.createElement(List, {data: this.state.list}),
// )

'div' - 直接渲染 <div> 便可,vdom能夠作到
Input 和 List ,是自定義組件(class),vdom 默認不認識
所以 Input 和 List 定義的時候必須聲明 render 函數
根據 props 初始化實例,而後執行實例的 render 函數
render 函數返回的仍是 vnode 對象

4.說一下 React setState 的過程
(1)setState 的異步(效果、緣由)
setState 爲什麼須要異步?
可能會一次執行屢次 setState
你沒法規定、限制用戶如何使用 setState
不必每次 setState 都從新渲染,考慮性能
即使是每次從新渲染,用戶也看不到中間的效果(JS執行的時候DOM渲染是阻塞的,單線程)
只看到最後的結果便可

(2)vue 修改屬性也是異步(效果、緣由)
效果、緣由和 setState 同樣
對比記憶,印象深入

(3)setState 的過程
每一個組件實例,都有 renderComponent 方法(繼承自 Component 類)
執行 renderComponent 會從新執行實例的render
render 函數返回 newVnode,而後拿到 preVnode
最終執行 patch(preVnode, newVnode)

5.React vs Vue,怎麼作技術選型

前言:
技術選型沒有絕對的對錯,技術選型要考慮的因素很是多,你要有本身的主見就行,只要能說出合理的理由。

(1)二者的本質區別
vue - 本質是 MVVM 框架,由 MVC 發展而來
React - 本質是前端組件化框架,由後端組件化發展而來
但這並不妨礙他們二者都能實現相同的功能

(2)看模板和組件化的區別
vue - 使用模板(最初由 angular 提出)
React - 使用 JSX
模板語法上,我更加傾向於 JSX
模板分離上,我更加傾向於 vue

模板的區別:
模板應該和 JS 邏輯分離(開放封閉原則)

組件化的區別:
React 自己就是組件化,沒有組件化就不是 React
vue 也支持組件化,不過是在 MVVM上的擴展
查閱 vue 組件化的文檔,洋洋灑灑不少還挺複雜(側面反映)
對於組件化,我更加傾向於 React,作的完全而清晰

(3)二者共同點
都支持組件化
都是數據驅動視圖

(4)總結問題答案
國內使用,首推 vue。文檔更易讀、易學、社區夠大。(團隊的技術不太紮實,沒有框架經驗,首推 vue)
若是團隊水平較高經驗較豐富,推薦使用 React。組件化和JSX,組件化作得完全而清晰,JSX也趨向於標準化

7.hybrid

前言
移動端佔大部分流量,已經遠遠超過PC
一線互聯網公司都有本身的APP
這些APP中有很大比例的前端代碼
那微信舉例,你天天瀏覽微信的內容,多少是前端?

1.hybrid 是什麼,爲什麼用 hybrid?
(1)hybrid 文字解釋
hybrid 即「混合」,即前端和客戶端的混合開發
需前端開發人員和客戶端開發人員配合完成
某些環節也可能涉及到 server 端

(2)存在價值,爲什麼會用 hybrid
能夠快速迭代更新【關鍵】(無需app審覈,思考爲什麼?)
體驗流暢(和NA的體驗基本相似)
減小開發和溝通成本,雙端公用一套代碼

(3)webview
是app中的一個組件(app能夠有webview,也能夠沒有)
用於加載 h5 頁面,即一個小型的瀏覽器內核

(4)file:// 協議
其實在一開始接觸 html 開發,就已經使用了 file 協議
只不過你當時沒有 「協議」 「標準」 等這些概念
再次強調 「協議」 「標準」 的重要性!!!

file 協議和 http 協議區別
file 協議:本地文件,快
http(s) 協議:網絡加載,慢

(5)hybrid 實現流程
不是全部場景都適合使用 hybrid
使用NA:提要要求極致,變化不頻繁(如頭條的首頁)
使用hybrid:體驗要求高,變化頻繁(如頭條的新聞詳情頁)
使用h5:體驗無要求,不經常使用(如舉報、反饋等頁面)

前端作好靜態頁面(html js css),將文件交給客戶端
客戶端拿到前端靜態頁面,以文件形式存儲在app中
客戶端在一個 webview 中,使用file協議加載靜態頁面

解答:
hybrid 是客戶端和前端的混合開發
hybrid 存在的核心意義在於快速迭代,無需審覈
hybrid 實現流程(圖),以及 webview 和 file 協議

2.介紹一下 hybrid 更新和上線的流程?
前提:
要替換每一個客戶端的靜態文件
只能客戶端來作(客戶端是咱們開發的)
客戶端去 server 下載最新的靜態文件
咱們維護 server 的靜態文件

完整流程:
分版本,有版本號,如 201910030916
將靜態文件壓縮成 zip 包,上傳到服務端
客戶端每次啓動,都去服務端檢查版本號
若是服務端版本號大於客戶端版本號,就去下載最新的 zip 包
下載完以後解壓包,而後將現有文件覆蓋

掌握流程圖
要點1:服務端的版本和 zip 包維護
要點2:更新 zip 包以前,先對比版本號
要點3:zip 下載解壓和覆蓋

3.hybrid 和 h5 的主要區別?
(1)優勢:
體驗更好,跟NA體驗基本一致
可快速迭代,無需app審覈(關鍵)
(2)缺點:
開發成本高。聯調、測試、查bug都比較麻煩
運維成本高。參考更新上線的流程
(3)適用的場景:
hybrid:產品的穩定功能,體驗要求高,迭代頻繁
h5:單次的運營活動(如xx紅包)或不經常使用功能

優勢:體驗好,可快速迭代
缺點:開發成本高,運維成本高
適用的場景:hybrid 適合產品型,h5 適用運營型

4.前端 JS 和客戶端如何通信?
(1)回顧遺留問題
新聞詳情頁適用 hybrid ,前端如何獲取新聞內容?
不能用 ajax 獲取。第一跨域(還能解決),第二速度慢
客戶端獲取新聞內容,而後JS通信拿到內容,再渲染

(2)JS 和客戶端通信的基本形式
JS 訪問客戶端能力,傳遞參數和回調函數
客戶端經過回調函數返回內容

(3)schema 協議簡介和使用
schema 協議——前端和客戶端通信的約定

<button id="btn">掃一掃</button>
<script>
    function invokeScan() {
        window['_invoke_scan_callback_'] = function (result) {
            alert(result);
        };

        var iframe = document.createElement('iframe');
        iframe.style.display = 'none';
        iframe.src = 'weixin://dl/scan?k1=v1&k2=v2&callback=_invoke_scan_callback_';
        var body = document.body;
        body.appendChild(iframe);
        setTimeout(function () {
            body.removeChild(iframe);
            iframe = null;
        });
    }

    document.getElementById('btn').addEventListener('click', function () {
        invokeScan();
    });
</script>

(4)schema 使用的封裝

invoke.js

(function (window) {
    // 調用 schema 的封裝
    function _invoke (action, data, callback) {
        // 拼接 schema 協議
        var schema = 'myapp://utils/' + action;

        // 拼接參數
        schema += '?a=a';
        var key;
        for(key in data) {
            if (data.hasOwnProperty(key)) {
                schema += '&' + key + '=' + data[key];
            }
        }

        // 處理 callback
        var callbackName = '';
        if (typeof callback === 'string') {
            callbackName = callback;
        } else {
            callbackName = action + Date.now();
            window[callbackName] = callback;
        }

        schema += '&callback=' + callbackName;

        // 觸發
        var iframe = document.createElement('iframe');
        iframe.style.display = 'none';
        iframe.src = schema;  // 重要
        var body = document.body;
        body.appendChild(iframe);
        setTimeout(function () {
            body.removeChild(iframe);
            iframe = null;
        });
    }

    // 暴露到全局變量
    window.invoke = {
        share: function (data, callback) {
            _invoke('share', data, callback);
        },
        scan: function (data, callback) {
            _invoke('scan', data, callback);
        },
        login: function (data, callback) {
            _invoke('login', data, callback);
        },
    }
})(window);
<button id="btn1">掃一掃</button>
<button id="btn2">分享</button>

<script src="invoke.js"></script>
<script>
    document.getElementById('btn1').addEventListener('click', function () {
        window.invoke.scan({}, function () {});
    });

    document.getElementById('btn2').addEventListener('click', function () {
        window.invoke.share({
            title: 'xxx',
            content: 'yyy'
        }, function (result) {
            if (result.errno === 0) {
                alert('分享成功');
            } else {
                alert(result.message);
            }
        });
    });
</script>

(5)內置上線
將封裝的代碼打包,叫作 invoke.js ,內置到客戶端
客戶端每次啓動 webview ,都默認執行 invoke.js
本地加載,免去網絡加載的時間,更快
本地加載,沒有網絡請求,黑客看不到 schema 協議,更安全

解答: 通信的基本形式:調用能力,傳遞參數,監聽回調 對 schema 協議的理解和使用 調用 schema 代碼的封裝 內置上線的好處:更快、更安全

相關文章
相關標籤/搜索