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 代码的封装 内置上线的好处:更快、更安全

相关文章
相关标签/搜索