Giter Club home page Giter Club logo

blog's Introduction

Hi there 👋 Welcome to my GitHub!

┌───┐   ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┐
│Esc│   │ F1│ F2│ F3│ F4│ │ F5│ F6│ F7│ F8│ │ F9│F10│F11│F12│ │P/S│S L│P/B│  ┌┐    ┌┐    ┌┐
└───┘   └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┘  └┘    └┘    └┘
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ ┌───┬───┬───┐ ┌───┬───┬───┬───┐
│~ `│! 1│@ 2│# 3│$ 4│% 5│^ 6│& 7│* 8│( 9│) 0│_ -│+ =│ BacSp │ │Ins│Hom│PUp│ │N L│ / │ * │ - │
├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ ├───┼───┼───┤ ├───┼───┼───┼───┤
│ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │{ [│} ]│ | \ │ │Del│End│PDn│ │ 7 │ 8 │ 9 │   │
├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ └───┴───┴───┘ ├───┼───┼───┤ + │
│ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │: ;│" '│ Enter  │               │ 4 │ 5 │ 6 │   │
├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤     ┌───┐     ├───┼───┼───┼───┤
│ Shift  │ Z │ X │ C │ V │ B │ N │ M │< ,│> .│? /│  Shift   │     │ ↑ │     │ 1 │ 2 │ 3 │   │
├─────┬──┴─┬─┴──┬┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ ┌───┼───┼───┐ ├───┴───┼───┤ E││
│ Ctrl│    │Alt │         Space         │ Alt│ Fn │    │Ctrl│ │ ← │ ↓ │ → │ │   0   │ . │←─┘│
└─────┴────┴────┴───────────────────────┴────┴────┴────┴────┘ └───┴───┴───┘ └───────┴───┴───┘

blog's People

Contributors

dependabot[bot] avatar surile avatar

blog's Issues

React Native 安卓原生角标

使用友盟推送,发现没有集成设置角标功能,因此就自己查阅文档等方式写了一个设置角标的功能。笔者安卓小白,不懂安卓,大神勿喷。

React Native 已提供Ios版插件,但对Android并未支持。国内安卓基本上都是深度定制过的,各方产商定制方法各不相同,我选择使用第三方开源的项目实现。

环境

    "react": "16.9.0",
    "react-native": "0.61.4",

安卓第三方插件

ShortcutBadger

ShortcutBadger 引入

  • 修改android/app/build.gradle
...
dependencies {
    implementation "me.leolin:ShortcutBadger:1.1.22@aar"
    ...
}
....

image

实现原生与ReactNative通信

  • 新建badge文件夹

  • 在badge文件夹中,新建 ShortcutBadgerModule(类)文件 继承 ReacContextBaseJavaModule

package com.jgadasdapp;  引入自己的包名

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import me.leolin.shortcutbadger.ShortcutBadger; // 引入外部导入的第三方包


public class ShortcutBadgerModule extends ReactContextBaseJavaModule {
    static ReactApplicationContext context;

    public ShortcutBadgerModule(ReactApplicationContext reactContext) {
        super(reactContext);
        context = reactContext;
    }

    /**
     * 这个返回的字符串是我们js端调用时会用到的
     */
    @Override
    public String getName() {
        return "ShortcutBadger";
    }

    /**
    *这个方法是我们js端调用的方法,其中的参数可以从js端传过来  如这里我们js端可以类似  Badge.applyCount(2)来调用这个方法
    */
    
    @ReactMethod
    public void applyCount(int badgeCount){
        if(context != null){
            ShortcutBadger.applyCount(context,badgeCount);
        }   
    }

    @ReactMethod
    public void removeCount(){
        if(context != null){
            ShortcutBadger.removeCount(context);
        }
    }
}
  • 注册模块

新建 ShortcutBadgerReactPackage(包)文件 继承 ReactPackage

package com.jgadasdapp;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.react.uimanager.ViewManager;
import com.more.shop.badge.ShortcutBadgerModule;

/**
 * Created by surile on 13/5/20.
 */

public class ShortcutBadgerReactPackage implements ReactPackage {

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    /**
     * 如需要添加本地方法,只需在这里add
     *
     * @param reactContext
     * @return
     */
    @Override
    public List<NativeModule> createNativeModules(
        ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new ShortcutBadgerModule(reactContext));
        return modules;
    }
}
  • 在 MainApplication 里面注册 ShortcutBadgerReactPackage
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // Packages that cannot be autolinked yet can be added manually here, for example:
          // packages.add(new MyReactNativePackage());
          packages.add(new ShortcutBadgerReactPackage());
          return packages;
        }

ReactNative 中调用

  • 引入 NativeModules
import {NativeModules, Platform} from 'react-native';
const ShortcutBadgerModule = NativeModules.ShortcutBadger;
  • 设置角标
ShortcutBadgerModule.applyCount(1)
  • 清除角标
ShortcutBadgerModule.removeCount()

参考

原生模块
友盟推送

setState为什么是异步?

笔者曾一直以为setState是异步的,并非是同步的,直到前一阵子同事问我React中的setState是异步还是同步.....

为什么要这么做

1. 保证内部的一致性

即使state是同步更新,props也不是。(只有在父组件重新渲染时才能知道props)

2. 性能优化

将state的更新延缓到最后批量合并再去渲染对于应用的性能优化是有极大好处,如果每次的状态改变都会去重新渲染真实的dom,将会带来巨大的性能消耗。

原理解释

setState并不是真正意义上的异步操作,只是模拟了异步的行为,其实官方已经给出答案,setState并不是真正的异步

class App extends Component {
  state = {
    count: 0
  };

  componentDidMount() {
    // 生命周期中调用
    this.setState({ count: this.state.count + 1 });
    console.log("lifecycle: " + this.state.count);
    setTimeout(() => {
      // setTimeout中调用
      this.setState({ count: this.state.count + 1 });
      console.log("setTimeout: " + this.state.count);
    }, 0);
    document.getElementById("div2").addEventListener("click", this.increment2);
  }

  increment = () => {
    // 合成事件中调用
    this.setState({ count: this.state.count + 1 });
    console.log("react event: " + this.state.count);
  };

  increment2 = () => {
    // 原生事件中调用
    this.setState({ count: this.state.count + 1 });
    console.log("dom event: " + this.state.count);
  };

  render() {
    return (
      <div className="App">
        <h2>couont: {this.state.count}</h2>
        <div id="div1" onClick={this.increment}>
          click me and count+1
        </div>
        <div id="div2">click me and count+1</div>
      </div>
    );
  }
}

探讨前,我们先简单了解下react的事件机制:react为了解决跨平台,兼容性问题,自己封装了一套事件机制,代理了原生的事件,像在jsx中常见的onClickonChange这些都是合成事件。

那么以上4种方式调用setState(),后面紧接着去取最新的state,按之前讲的异步原理,应该是取不到的。然而,setTimeout中调用以及原生事件中调用的话,是可以立马获取到最新的state的。根本原因在于,setState并不是真正意义上的异步操作,它只是模拟了异步的行为。React中会去维护一个标识(isBatchingUpdates),判断是直接更新还是先暂存state进队列。setTimeout以及原生事件都会直接去更新state,因此可以立即得到最新state。而合成事件和React生命周期函数中,是受React控制的,其会将isBatchingUpdates设置为 true,从而走的是类似异步的那一套。

在 setTimeout 中去 setState 并不算是一个单独的场景,它是随着你外层去决定的,因为你可以在合成事件中 setTimeout ,可以在钩子函数中 setTimeout ,也可以在原生事件setTimeout,但是不管是哪个场景下,基于event loop的模型下, setTimeout 中里去 setState 总能拿到最新的state值。

总结

  1. setState 只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中都是同步的。
  2. setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
  3. setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。

Javascript递归处理数组

前端添加数据,未进入数据库,因此选中的数据,是由name组成,后台将数据返回时,带有id,不能进行删除操作,只能进行修改name操作,因原先是由name组成数据,为了匹配修改的数据,所以要将选中的数据,转化成id

手动定义数据结构

let data = [{
    // 规格名称,可修改
    kindName: "二级规格",
    customValue: "",
    // 已选中
    specificationsName: ["测试","测试2"],
    dialogVisible: false,
    // 默认所有的数据,未选中和已选中的数据都在里面
    defaultSpecificationsName: [
        {
            id:1,
            name: "测试",
            
        },
        {
            id:2,
            name: "测试2",
            child:[
                {
                    kindName:"测试2",
                    customValue:"",
                    specificationsName:["测试3"],
                    dialogVisible:false,
                    defaultSpecificationsName:[
                        {
                            id:3,
                            name:"测试3"
                        }
                    ]
                }
            ]
        }
    ]
}]

递归函数

写成公共递归函数,可根据name获取id,也可以根据id获取name,方便提交数据。

let traversalIds = (setValues,value) => {    
    // setValues 传递的data数组,value是参数,若是需要获取id,则传入的是name,反之。
    setValues.forEach(item => {
        let specificationName = []
        item.specificationsName.forEach(o => {
            item.defaultSpecificationsName.forEach(i => {
                if(i.child && i.child instanceof Array){
                    onTraversalIds(i.child,value)
                }
                if(o === i[value]){
                   // 判断specificationsName中的id或name是否等于
                    specificationName.push(i[value])
                }
                item.specificationsName = specificationName // 修改某数据下的specificationName
            })
        })
    })
    return setValues   // 将以修改的数据返回
}

平级数据

将所有选中的数据,添加至一个数组中,pid是关联父id

let TraversalArray = (setValues,pid) => {
    let specifications = []
    for(let index = 0;index < setValues.length;index++){
       const data = setValues[index]
       data.specificationsName.forEach(name => {
           data.defaultSpecificationsName.forEach(item => {
               // 判断name是否相等
               if(name == item.name){
                   // 若是相等,则添加至数组中
                   specifications.push({
                       id:item.id ? item.id : "",
                       pid:pid,
                       name:item.name
                   })
                   // 循环数组,若是没有pid,将pid删除
                   specifications.map(o => {
                       if(!o.pid){
                          delete o.pid 
                       }
                   })
                  // 终止结束
                  return
               }
              // 判断是否有child
               if(item.child && item.child instanceof Array){
                  // 重新调用此函数,并将父id传递到此函数中
                   const obj = TraversalArray(item.child,item.id)
                  // 判断返回的数据是否是数组
                   if(obj instanceof Array){
                      // 如果是合并两个数组,并将合并的数组返回
                      specifications = [...specifications,...obj]
                      return specifications
                   }
               }
           })
       })
    }
    return specifications
}

利用git subtree部署项目到GitHub

git subtree 教程


关于子仓库或者说是仓库共用,git官方推荐的工具是git subtree。 我自己也用了一段时间的git subtree,感觉比git submodule好用,但是也有一缺点,在可接受的范围内。所以对于仓库共用,在git subtree 与 git submodule之中选择的话,我推荐git subtree。

git subtree是什么?为什么使用git subtree


git subtree 可以实现一个仓库作为其他仓库的子仓库。

image

使用git subtree 有以下几个原因:

  • 旧版本的git也支持(最老版本可以到 v1.5.2).
  • git subtree与git submodule不同,它不增加任何像.gitmodule这样的新的元数据文件.
  • git subtree对于项目中的其他成员透明,意味着可以不知道git subtree的存在.
    当然,git subtree也有它的缺点,但是这些缺点还在可以接受的范围内:
  • 必须学习新的指令(如:git subtree).
  • 子仓库的更新与推送指令相对复杂。

git subtree 的使用


git subtree的主要命令有:

 git subtree add   --prefix=<prefix> <commit>
 git subtree add   --prefix=<prefix> <repository> <ref>
 git subtree pull  --prefix=<prefix> <repository> <ref>
 git subtree push  --prefix=<prefix> <repository> <ref>
 git subtree merge --prefix=<prefix> <commit>
 git subtree split --prefix=<prefix> [OPTIONS] [<commit>]

准备


我们先在github 中创建vue-login,然后按照 GitHub 上的提示将项目克隆到本地

     git clone https://github.com/surile/vue-login.git

vue-login的路径为https://github.com/surile/vue-login.git,仓库里的文件有:

     vue-login
     |
     |-- build
     |-- pulish
     |-- src
     |-- webpack.common.js
     |-- webpack.prod.js
     |-- webpack.dev.js
     \-- README.md

以下操作均位于根目录中。
我们执行以下命令把master 分支中的 build 文件推送到远程仓库gh-pages分支中:

    yarn build || npm run build
    git checkout -b gh-pages
    git add -f build
    git commit -m 'created gh-pages'
    git subtree push --prefix build origin gh-pages

这步做完之后就可以在 GitHub 上看见 gh-pages 分支了。GitHub 会自动部署 gh-pages 里的静态文件。
点开 Settings,将会看到以下内容。勾出绿色部分则是你的URL

image

当我们修改项目完成之后,肯定是要从前 build 的。这时使用以下命令,则就没用了。

     yarn build || npm run build
     git add -f build
     git commit -m '重新 build'
     git subtree push --prefix build origin gh-pages

会出现以下错误。
image

出现这种错误,根据提示我们可以看出来,是要让我们强行将 build 推送到远程gh-pages 分支上,则可以用以下命令

     git push origin `git subtree split --prefix build master`:gh-pages --force

image

运行命令,则可以强制将 build 文件夹推送到远程 gh-pages 分支上了。

vue静态资源打包中的坑与解决方案

vue静态资源打包中的坑与解决方案


前言

记录一下在使用 vue-cli 时的坑,vue-cli 脚手架生成的默认打包配置文件情况下运行 npm run build || yarn build 打包后静态文件出现404

image

以上图,就是出现的问题

如何解决:
vue-cli 官方文档已经说明。请看图。
image

vue 官方文档说明是在 vue.config.js 将 baseUrl 修改
按照官方文档修改,发现再次运行build时,就没有出现静态文件404

如何让pm2支持es6

前言

就如同标题一样如何让pm2支持es6,现在 es6已经是满天飞了,写 node 的时候肯定也要用es6咯,所以才会出现如何将pm2支持es6。

PM2官网介绍

PM2官网介绍

问题是我按照官网介绍使用之后还是不能让 pm2 支持es6,好烦。。。

重新看了下官网文档,看到有这么一段

PM2

其实这段代码 我在对应的ecosystem.config.js(简单说 就是pm2的配置文件,类似npm的package.json)里写过对应的,但没起作用。看到这我才明白为啥没起作用: pm2默认服务是负载均衡的,注意红框中的话:没错,它只能工作在fork模式下。所以我那就一直没跑起来。

但如果不用负载均衡,感觉又何必用pm2呢?它的优势不就是这个吗?所以又往下看。果然,pm2提供了解决方法:

单写一个js文件,内容如下。pm2 直接运行这个文件即可。既解决了koa的es6编译的问题,又能使用pm2的负载均衡。以下内容只能解决 import

Import

运行起来,PM25的状态是 online,但是查看 PM2 logs 时发现报错了。特么我以为以上命令是支持所有 es6,没想到却报以下错误

2018-08-18-16-38-29

wtf,竟然又报错。我就去谷歌,找了半天找到了。

还是一样单写一个 js,内容如下。pm2直接运行这个文件就可以了。

2018-08-18-16-39-42

我在去查看 logs 时,终于没在报错了。(^▽^)。完美的解决了我的问题。hhhhhh

零基础学习测试

学习思路

软件测试学习路线图:

第一阶段:前置基础知识

第一阶段

基础打牢固,你需要学习的教程

零基础学习5天

提取码:hvsn

第二阶段:Linux和数据库

第一阶段

学习这一阶段可以看下面的教程:

软件测试必会的linux快速入门教程
提取码: p9sh

软件测试教程两天搞定Mysql
提取码:ysne

第三阶段:测试基础

测试基础

这一阶段你要学习的教程:

深入了解软件测试4天视频
提取码: whd8

第四阶段:编程+数据结构

编程+数据结构

这一阶段需要学习的教程:

软件测试必知的Python技术
提取码: **imwg **

第五阶段:WEB自动化

这一阶段需要学习的教程:

2天web自动化入门教程
提取码: cnrp

第六阶段:移动自动化

这一阶段需要学习的教程:

软件测试项目案例之移动端测试
提取码: kuk4

第七阶段:接口测试

这一阶段需要学习的教程:

2天带你掌握接口基础
提取码: 6bqv

第八阶段:性能测试

这一阶段需要学习的教程:

两天带你入门性能测试
提取码: ej4j

web前端面试

HTML

  • 行内元素有哪些?块级元素有哪些? 空(void)元素有那些?

      首先:CSS规范规定,每个元素都有display属性,确定该元素的类型,每个元素都有默认的display值,如div的display默认值为“block”,则为“块级”元素;span默认display属性值为“inline”,是“行内”元素。
    
      (1)行内元素有:a b span img input select strong(强调的语气)
      (2)块级元素有:div ul ol li dl dt dd h1 h2 h3 h4…p
    
      (3)常见的空元素:
      	<br> <hr> <img> <input> <link> <meta>
      	鲜为人知的是:
      	<area> <base> <col> <command> <embed> <keygen> <param> <source> <track> <wbr>
    
  • 常见的浏览器内核有哪些?

      Trident内核:IE,MaxThon,TT,The World,360,搜狗浏览器等。[又称MSHTML]
      Gecko内核:Netscape6及以上版本,FF,MozillaSuite/SeaMonkey等
      Presto内核:Opera7及以上。      [Opera内核原为:Presto,现为:Blink;]
      Webkit内核:Safari,Chrome等。   [ Chrome的:Blink(WebKit的分支)]
    
    详细文章:[浏览器内核的解析和对比](http://www.cnblogs.com/fullhouse/archive/2011/12/19/2293455.html)
    
  • html5有哪些新特性、移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和 HTML5?

      * HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加。
      	  绘画 canvas;
      	  用于媒介回放的 video 和 audio 元素;
      	  本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;
            sessionStorage 的数据在浏览器关闭后自动删除;
      	  语意化更好的内容元素,比如 article、footer、header、nav、section;
      	  表单控件,calendar、date、time、email、url、search;
      	  新的技术webworker, websocket, Geolocation;
    
        移除的元素:
      	  纯表现的元素:basefont,big,center,font, s,strike,tt,u;
      	  对可用性产生负面影响的元素:frame,frameset,noframes;
    
      * 支持HTML5新标签:
      	 IE8/IE7/IE6支持通过document.createElement方法产生的标签,
        	 可以利用这一特性让这些浏览器支持HTML5新标签,
        	 浏览器支持新标签后,还需要添加标签默认的样式。
    
           当然也可以直接使用成熟的框架、比如html5shim;
      	 <!--[if lt IE 9]>
      		<script> src="http://html5shim.googlecode.com/svn/trunk/html5.js"</script>
      	 <![endif]-->
    
      * 如何区分HTML5: DOCTYPE声明\新增的结构元素\功能元素
    
  • 请描述一下 cookies,sessionStorage 和 localStorage 的区别?

      cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。
      cookie数据始终在同源的http请求中携带(即使不需要),记会在浏览器和服务器间来回传递。
      sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
    
      存储大小:
      	cookie数据大小不能超过4k。
      	sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
    
      有期时间:
      	localStorage    存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
      	sessionStorage  数据在当前浏览器窗口关闭后自动删除。
      	cookie          设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
    
  • HTML5的form如何关闭自动完成功能?

      给不想要提示的 form 或某个 input 设置为 autocomplete=off。
    

CSS

  • 介绍一下标准的CSS的盒子模型?低版本IE的盒子模型有什么不同的?

      (1)有两种, IE 盒子模型、W3C 盒子模型;
      (2)盒模型: 内容(content)、填充(padding)、边界(margin)、 边框(border);
      (3)区  别: IE的content部分把 border 和 padding计算了进去;
    
  • display有哪些值?说明他们的作用。

    block       	块类型。默认宽度为父元素宽度,可设置宽高,换行显示。
    none        	元素不显示,并从文档流中移除。
    inline      	行内元素类型。默认宽度为内容宽度,不可设置宽高,同行显示。
    inline-block  默认宽度为内容宽度,可以设置宽高,同行显示。
    list-item   	象块类型元素一样显示,并添加样式列表标记。
    table       	此元素会作为块级表格来显示。
    inherit     	规定应该从父元素继承 display 属性的值。
  • position的值relative和absolute定位原点是?
    absolute
  	生成绝对定位的元素,相对于值不为 static的第一个父元素进行定位。
    fixed (老IE不支持)
  	生成绝对定位的元素,相对于浏览器窗口进行定位。
    relative
  	生成相对定位的元素,相对于其正常位置进行定位。
    static
  	默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right z-index 声明)。
    inherit
  	规定从父元素继承 position 属性的值。
  • 为什么要初始化CSS样式。
  - 因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对CSS初始化往往会出现浏览器之间的页面显示差异。

  - 当然,初始化样式会对SEO有一定的影响,但鱼和熊掌不可兼得,但力求影响最小的情况下初始化。

  最简单的初始化方法: * {padding: 0; margin: 0;} (强烈不建议)

  淘宝的样式初始化代码:
  body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { margin:0; padding:0; }
  body, button, input, select, textarea { font:12px/1.5tahoma, arial, \5b8b\4f53; }
  h1, h2, h3, h4, h5, h6{ font-size:100%; }
  address, cite, dfn, em, var { font-style:normal; }
  code, kbd, pre, samp { font-family:couriernew, courier, monospace; }
  small{ font-size:12px; }
  ul, ol { list-style:none; }
  a { text-decoration:none; }
  a:hover { text-decoration:underline; }
  sup { vertical-align:text-top; }
  sub{ vertical-align:text-bottom; }
  legend { color:#000; }
  fieldset, img { border:0; }
  button, input, select, textarea { font-size:100%; }
  table { border-collapse:collapse; border-spacing:0; }
  • 如果需要手动写动画,你认为最小时间间隔是多久,为什么?
多数显示器默认频率是60Hz,即1秒刷新60次,所以理论上最小间隔为1/60*1000ms = 16.7ms
  • rem布局的优缺点

  • CSS选择符有哪些?哪些属性可以继承?

      *   1.id选择器( # myid)
      	2.类选择器(.myclassname)
      	3.标签选择器(div, h1, p)
      	4.相邻选择器(h1 + p)
      	5.子选择器(ul > li)
      	6.后代选择器(li a)
      	7.通配符选择器( * )
      	8.属性选择器(a[rel = "external"])
      	9.伪类选择器(a:hover, li:nth-child)
    
      *   可继承的样式: font-size font-family color, UL LI DL DD DT;
    
      *   不可继承的样式:border padding margin width height ;
    
  • CSS优先级算法如何计算?

      *   优先级就近原则,同权重情况下样式定义最近者为准;
      *   载入样式以最后载入的定位为准;
    
      优先级为:
      	同权重: 内联样式表(标签内部)> 嵌入样式表(当前文件中)> 外部样式表(外部文件中)。
      	!important >  id > class > tag
      	important 比 内联优先级高
    
  • CSS3新增伪类有那些?

      	举例:
      	p:first-of-type	选择属于其父元素的首个 <p> 元素的每个 <p> 元素。
      	p:last-of-type	选择属于其父元素的最后 <p> 元素的每个 <p> 元素。
          p:only-of-type	选择属于其父元素唯一的 <p> 元素的每个 <p> 元素。
      	p:only-child		选择属于其父元素的唯一子元素的每个 <p> 元素。
      	p:nth-child(2)	选择属于其父元素的第二个子元素的每个 <p> 元素。
    
      	::after			在元素之前添加内容,也可以用来做清除浮动。
      	::before			在元素之后添加内容
          :enabled  		
      	:disabled 		控制表单控件的禁用状态。
      	:checked        单选框或复选框被选中。
    
  • li与li之间有看不见的空白间隔是什么原因引起的?有什么解决办法?

      行框的排列会受到中间空白(回车\空格)等的影响,因为空格也属于字符,这些空白也会被应用样式,占据空间,所以会有间隔,把字符大小设为0,就没有空格了。
    
  • 为什么要初始化CSS样式。

      - 因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对CSS初始化往往会出现浏览器之间的页面显示差异。
    
      - 当然,初始化样式会对SEO有一定的影响,但鱼和熊掌不可兼得,但力求影响最小的情况下初始化。
    
      最简单的初始化方法: * {padding: 0; margin: 0;} (强烈不建议)
    
      淘宝的样式初始化代码:
      body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { margin:0; padding:0; }
      body, button, input, select, textarea { font:12px/1.5tahoma, arial, \5b8b\4f53; }
      h1, h2, h3, h4, h5, h6{ font-size:100%; }
      address, cite, dfn, em, var { font-style:normal; }
      code, kbd, pre, samp { font-family:couriernew, courier, monospace; }
      small{ font-size:12px; }
      ul, ol { list-style:none; }
      a { text-decoration:none; }
      a:hover { text-decoration:underline; }
      sup { vertical-align:text-top; }
      sub{ vertical-align:text-bottom; }
      legend { color:#000; }
      fieldset, img { border:0; }
      button, input, select, textarea { font-size:100%; }
      table { border-collapse:collapse; border-spacing:0; }
    
  • 请解释一下为什么需要清除浮动?清除浮动的方式

    清除浮动是为了清除使用浮动元素产生的影响。浮动的元素,高度会塌陷,而高度的塌陷使我们页面后面的布局不能正常显示。

      1、父级div定义height;
      2、父级div 也一起浮动;
      3、常规的使用一个class;
      	.clearfix::before, .clearfix::after {
      	    content: " ";
      	    display: table;
      	}
      	.clearfix::after {
      	    clear: both;
      	}
      	.clearfix {
      	    *zoom: 1;
      	}
    
      4、SASS编译的时候,浮动元素的父级div定义伪类:after
      	&::after,&::before{
      	    content: " ";
              visibility: hidden;
              display: block;
              height: 0;
              clear: both;
      	}
    
      解析原理:
      1) display:block 使生成的元素以块级元素显示,占满剩余空间;
      2) height:0 避免生成内容破坏原有布局的高度。
      3) visibility:hidden 使生成的内容不可见,并允许可能被生成内容盖住的内容可以进行点击和交互;
      4)通过 content:"."生成内容作为最后一个元素,至于content里面是点还是其他都是可以的,例如oocss里面就有经典的 content:".",有些版本可能content 里面内容为空,一丝冰凉是不推荐这样做的,firefox直到7.0 content:”" 仍然会产生额外的空隙;
      5)zoom:1 触发IE hasLayout。
    
      通过分析发现,除了clear:both用来闭合浮动的,其他代码无非都是为了隐藏掉content生成的内容,这也就是其他版本的闭合浮动为什么会有font-size:0,line-height:0。
    
  • 什么是外边距合并?

      外边距合并指的是,当两个垂直外边距相遇时,它们将形成一个外边距。
      合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。
      w3school介绍网址: http://www.w3school.com.cn/css/css_margin_collapsing.asp
      
      - 移动端的布局用过媒体查询吗?
    

    假设你现在正用一台显示设备来阅读这篇文章,同时你也想把它投影到屏幕上,或者打印出来,
    而显示设备、屏幕投影和打印等这些媒介都有自己的特点,CSS就是为文档提供在不同媒介上展示的适配方法

    当媒体查询为真时,相关的样式表或样式规则会按照正常的级联规被应用。
    当媒体查询返回假, 标签上带有媒体查询的样式表 仍将被下载 (只不过不会被应用)。

    包含了一个媒体类型和至少一个使用 宽度、高度和颜色等媒体属性来限制样式表范围的表达式。
    CSS3加入的媒体查询使得无需修改内容便可以使样式应用于某些特定的设备范围。

    <style> @media (min-width: 700px) and (orientation: landscape){ .sidebar { display: none; } } </style>
  • 使用 CSS 预处理器吗?喜欢那个?

      SASS (SASS、LESS没有本质区别,只因为团队前端都是用的SASS)
    
  • CSS优化、提高性能的方法有哪些?

      关键选择器(key selector)。选择器的最后面的部分为关键选择器(即用来匹配目标元素的部分);
      如果规则拥有 ID 选择器作为其关键选择器,则不要为规则增加标签。过滤掉无关的规则(这样样式系统就不会浪费时间去匹配它们了);
      提取项目的通用公有样式,增强可复用性,按模块编写组件;增强项目的协同开发性、可维护性和可扩展性;
      使用预处理工具或构建工具(gulp对css进行语法检查、自动补前缀、打包压缩、自动优雅降级);
    
  • 浏览器是怎样解析CSS选择器的?

      样式系统从关键选择器开始匹配,然后左移查找规则选择器的祖先元素。
      只要选择器的子树一直在工作,样式系统就会持续左移,直到和规则匹配,或者是因为不匹配而放弃该规则。
    
  • margin和padding分别适合什么场景使用?

      margin是用来隔开元素与元素的间距;padding是用来隔开元素与内容的间隔。
      margin用于布局分开元素使元素与元素互不相干;
      padding用于元素与内容之间的间隔,让内容(文字)与(包裹)元素之间有一段
    
  • 什么是响应式设计?响应式设计的基本原理是什么?如何兼容低版本的IE?

  • 如果需要手动写动画,你认为最小时间间隔是多久,为什么?(阿里)

      多数显示器默认频率是60Hz,即1秒刷新60次,所以理论上最小间隔为1/60*1000ms = 16.7ms
    
  • 什么是CSS 预处理器 / 后处理器?

      - 预处理器例如:LESS、Sass、Stylus,用来预编译Sass或less,增强了css代码的复用性,
        还有层级、mixin、变量、循环、函数等,具有很方便的UI组件模块化开发能力,极大的提高工作效率。
    
      - 后处理器例如:PostCSS,通常被视为在完成的样式表中根据CSS规范处理CSS,让其更有效;目前最常做的
        是给CSS属性添加浏览器私有前缀,实现跨浏览器兼容性的问题。
    

JavaScript

  • 介绍js的基本数据类型。

      Undefined、Null、Boolean、Number、String、
      ECMAScript 2015 新增:Symbol(创建后独一无二且不可变的数据类型 )
    
  • 介绍js有哪些内置对象?

     Object 是 JavaScript 中所有对象的父对象
    
     数据封装类对象:Object、Array、Boolean、Number 和 String
     其他对象:Function、Arguments、Math、Date、RegExp、Error
    
     参考:http://www.ibm.com/developerworks/cn/web/wa-objectsinjs-v1b/index.html
    
  • JavaScript原型,原型链 ? 有什么特点?

     每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,
     如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,
     于是就这样一直找下去,也就是我们平时所说的原型链的概念。
     关系:instance.constructor.prototype = instance.__proto__
    
     特点:
     JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。
    
    
      当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的话,
      就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象。
     	function Func(){}
     	Func.prototype.name = "Sean";
     	Func.prototype.getInfo = function() {
     	  return this.name;
     	}
     	var person = new Func();//现在可以参考var person = Object.create(oldObject);
     	console.log(person.getInfo());//它拥有了Func的属性和方法
     	//"Sean"
     	console.log(Func.prototype);
     	// Func { name="Sean", getInfo=function()}
    
  • Javascript作用链域?

     全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节。
     当需要从局部函数查找某一属性或方法时,如果当前作用域没有找到,就会上溯到上层作用域查找,
     直至全局函数,这种组织形式就是作用域链。
    
  • Javascript如何实现继承?

     1、构造继承
     2、原型继承
     3、实例继承
     4、拷贝继承
    
     原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式。
     
     	function Parent(){
     		this.name = 'wang';
     	}
    
     	function Child(){
     		this.age = 28;
     	}
     	Child.prototype = new Parent();//继承了Parent,通过原型
    
     	var demo = new Child();
     	alert(demo.age);
     	alert(demo.name);//得到被继承的属性
    
  • JavaScript继承的几种实现方式?

  • 谈谈This对象的理解。

    this总是指向函数的直接调用者(而非间接调用者);
    如果有new关键字,this指向new出来的那个对象;
    在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window;
    
  • ["1", "2", "3"].map(parseInt) 答案是多少?

     parseInt() 函数能解析一个字符串,并返回一个整数,需要两个参数 (val, radix),
     其中 radix 表示要解析的数字的基数。【该值介于 2 ~ 36 之间,并且字符串中的数字不能大于radix才能正确返回数字结果值】;
     但此处 map 传了 3 个 (element, index, array),我们重写parseInt函数测试一下是否符合上面的规则。
    
     function parseInt(str, radix) {
         return str+'-'+radix;
     };
     var a=["1", "2", "3"];
     a.map(parseInt);  // ["1-0", "2-1", "3-2"] 不能大于radix
    
     因为二进制里面,没有数字3,导致出现超范围的radix赋值和不合法的进制解析,才会返回NaN
     所以["1", "2", "3"].map(parseInt) 答案也就是:[1, NaN, NaN]
    
     详细解析:http://blog.csdn.net/justjavac/article/details/19473199
    
  • 如何判断一个对象是否属于某个类?

       使用instanceof (待完善)
        if(a instanceof Person){
            alert('yes');
        }
    
  • 同步和异步的区别?

    同步的概念应该是来自于OS中关于同步的概念:不同进程为协同完成某项工作而在先后次序上调整(通过阻塞,唤醒等方式).同步强调的是顺序性.谁先谁后.异步则不存在这种顺序性.

    同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作。

    异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容。

  • .call() 和 .apply() 的区别?

       例子中用 add 来替换 sub,add.call(sub,3,1) == add(3,1) ,所以运行结果为:alert(4);
    
       注意:js 中的函数其实是对象,函数名是对 Function 对象的引用。
    
     	function add(a,b)
     	{
     	    alert(a+b);
     	}
    
     	function sub(a,b)
     	{
     	    alert(a-b);
     	}
    
     	add.call(sub,3,1);
    
  • 知道各种JS框架(Angular, Backbone, Ember, React, Meteor, Knockout...)么? 能讲出他们各自的优点和缺点么?

  • 那些操作会造成内存泄漏?

     内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。
     垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。
    
     setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
     闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
    
  • 检测浏览器版本版本有哪些方式?

      功能检测、userAgent特征检测
    
      比如:navigator.userAgent
      //"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36
        (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36"
    
  • Webpack热更新实现原理?

      1. Webpack编译期,为需要热更新的 entry 注入热更新代码(EventSource通信)
      2. 页面首次打开后,服务端与客户端通过 EventSource 建立通信渠道,把下一次的 hash 返回前端
      3. 客户端获取到hash,这个hash将作为下一次请求服务端 hot-update.js 和 hot-update.json的hash
      4. 修改页面代码后,Webpack 监听到文件修改后,开始编译,编译完成后,发送 build 消息给客户端
      5. 客户端获取到hash,成功后客户端构造hot-update.js script链接,然后插入主文档
      6. hot-update.js 插入成功后,执行hotAPI 的 createRecord 和 reload方法,获取到 Vue 组件的 render方法,重新 render 组件, 继而实现 UI 无刷新更新。
    

ECMAScript6 相关

  • Object.is() 与原来的比较操作符“ ===”、“ ==”的区别?

      两等号判等,会在比较时进行类型转换;
      三等号判等(判断严格),比较时不进行隐式类型转换,(类型不同则会返回false);
    
      Object.is 在三等号判等的基础上特别处理了 NaN 、-0 和 +0 ,保证 -0 和 +0 不再相同,
      但 Object.is(NaN, NaN) 会返回 true.
    
      Object.is 应被认为有其特殊的用途,而不能用它认为它比其它的相等对比更宽松或严格。
    

React

  • React 使用场景?

      逻辑复杂单页应用,偏中后台管理系统,纯展示性的UI页面不合适、
    
  • React有什么特点?

      它使用**虚拟DOM **而不是真正的DOM。
      它可以用服务器端渲染。
      它遵循单向数据流或数据绑定。
    
  • 什么是 Props?

     Props 是 React 中属性的简写。它们是只读组件,必须保持纯,即不可变。它们总是在整个应用中从父组件传递到子组件。子组件永远不能将 prop 送回父组件。这有助于维护单向数据流,通常用于呈现动态生成的数据。
    
  • 描述一下React 生命周期

      渲染过程调用到的生命周期函数,主要几个要知道;
      * constructor

      * getInitialState

      * getDefaultProps

      * componentWillMount

      * render

      * componentDidMount

    
      更新过程
    
      * componentWillReceiveProps

      * shouldComponentUpdate

      * componentWillUpdate

      * render

      * componentDidUpdate

    
      卸载过程
    
      componentWillUnmount
    
  • 实现组件有哪些方式?

      React.createClass 使用API来定义组件
      React ES6 class component 用 ES6 的class 来定义组件
      Functional stateless component 通过函数定义无状态组件
    
  • 应该在React生命周期的什么阶段发出ajax请求,为什么?

      AJAX请求应在 componentDidMount函数 进行请求。
    
  • shouldComponentUpdate函数有什么作用?

      shouldComponentUpdate是一个允许我们自行决定某些组件(以及他们的子组件)是否进行更新的生命周期函数,reconciliation的最终目的是尽可能以最有效的方式去根据新的state更新UI,
      如果你已经知道UI的哪些状态无需进行改变,就没必要去让React去判断它是否该改变。 让shouldComponentUpdate返回falss, React就会让当前的组件和其子组件保持不变。
    
  • 当组件的setState函数被调用之后,发生了什么?

      React会做的第一件事就是把你传递给setState的参数对象合并到组件原先的state。这个事件会导致一个“reconciliation”(调和)的过程。reconciliation的最终目标就是,
      尽可能以最高效的方法,去基于新的state来更新UI。为了达到这个目的,React会构建一个React元素树(你可以把这个想象成一个表示UI的一个对象)。一旦这个树构建完毕,
      React为了根据新的state去决定UI要怎么进行改变,它会找出这棵新树和旧树的不同之处。React能够相对精确地找出哪些位置发生了改变以及如何发生了什么变化,
      并且知道如何只通过必要的更新来最小化重渲染。
    
  • 为什么循环产生的组件中要利用上key这个特殊的prop?

      Keys负责帮助React跟踪列表中哪些元素被改变/添加/移除。React利用子元素的key在比较两棵树的时候,快速得知一个元素是新的还是刚刚被移除。没有keys,React也就不知道当前哪一个的item被移除了。
    
  • 列出一些应该使用 Refs 的情况

      需要管理焦点、选择文本或媒体播放时
      触发式动画
      与第三方 DOM 库集成
    
  • Redux 的组件

      Action – 这是一个用来描述发生了什么事情的对象。
      Reducer – 这是一个确定状态将如何变化的地方。
      Store – 整个程序的状态/对象树保存在Store中。
      View – 只显示 Store 提供的数据
    

Vue

  • Vue的生命周期
    image
  • Vue在什么阶段才可以访问Dom
在钩子函数 mounted 被调用前,Vue 已经将编译好的模板挂载到页面上,所以在 mounted 中可以访问操作 DOM。vue 具体的生命周期示意图可以参见如下,理解了整个生命周期各个阶段的操作,关于生命周期相关的面试题就难不倒你了。
  • Vuex 的组件
State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中
  • 谈谈你对 keep-alive 的了解?
keep-alive  Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 ,其有以下特性:

一般结合路由和动态组件一起使用,用于缓存组件;
提供 include  exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;
对应两个钩子函数 activated  deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。
  • Vue 是如何实现数据双向绑定的?
Vue 主要通过以下 4 个步骤来实现数据双向绑定的:
实现一个监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty() 对属性都加上 setter  getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。
实现一个解析器 Compile:解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新。
实现一个订阅者 Watcher:Watcher 订阅者是 Observer  Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。
实现一个订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer  订阅者 Watcher 进行统一管理。
  • Proxy 与 Object.defineProperty 优劣对比
Proxy 的优势如下:

Proxy 可以直接监听对象而非属性;
Proxy 可以直接监听数组的变化;
Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的, Object.defineProperty 只能遍历对象属性直接修改;
Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;

Object.defineProperty 的优势如下:

兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。
  • $set在vue中解决了什么问题?
解决数据不能响应的问题 
  • 虚拟 DOM 实现原理?
虚拟 DOM 的实现原理主要包括以下 3 部分:

 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
diff 算法  比较两棵虚拟 DOM 树的差异;
pach 算法  将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
  • vue-router 路由模式有几种?
  3 种路由模式:hash、history、abstract,
  • Vue 组件间通信有哪几种方式?
1.props / $emit 适用 父子组件通信
2.ref  $parent / $children 适用 父子组件通信
3.EventBus ($emit / $on) 适用于 父子、隔代、兄弟组件通信
  • Vue-Router的原理是什么
  • 想在Vue中实现动态表单,如果实现
  • 不使用框架,如何手动实现一个菜单

React Native

  • React Native相对于原生的ios和Android有哪些优势?
1.性能媲美原生APP
2.使用JavaScript编码,只要学习这一种语言
3.绝大部分代码安卓和IOS都能共用
4.组件式开发,代码重用性很高
5.跟编写网页一般,修改代码后即可自动刷新,不需要慢慢编译,节省很多编译等待时间
6.支持APP热更新,更新无需重新安装APP
  • 有了解过React Native的原理吗?大概说一下你的理解?
   简述:主要是由JavaScriptCode
  • React Native是如何加载Bundle的机制?
要实现RN的脚本热更新,我们要搞明白RN是如何去加载脚本的。 在编写业务逻辑的时候,我们会有许多个js文件,打包的时候RN会将这些个js文件打包成一个叫index.android.bundle(ios的是index.ios.bundle)的文件,所有的js代码(包括rn源代码、第三方库、业务逻辑的代码)都在这一个文件里,启动App时会第一时间加载bundle文件,所以脚本热更新要做的事情就是替换掉这个bundle文件。
  • 如何在React Native中实现一个视频播放器?

  • 如何在React Native中实现实时地位?

  • 请简单说明一下热更新的原理

调用 react native 的打包命令,将当前环境的非 native 代码全量打包成一个 bundle 文件,然后上传到服务器中,  app 中启动页(或 splash 页)编写请求更新的代码(请求包含了本地版本,hashCode、appToken 等信息),对比本地 js bundle 版本和服务器上的版本,如果本地版本低,就下载新的 js ,如果相等或者小于服务器的版本号,则不更新。

其他问题

  • 一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
    注:这题胜在区分度高,知识点覆盖广,再不懂的人,也能答出几句,
    而高手可以根据自己擅长的领域自由发挥,从URL规范、HTTP协议、DNS、CDN、数据库查询、
    到浏览器流式解析、CSS规则构建、layout、paint、onload/domready、JS执行、JS API绑定等等;

    详细版:
  	1、浏览器会开启一个线程来处理这个请求,对 URL 分析判断如果是 http 协议就按照 Web 方式来处理;
  	2、调用浏览器内核中的对应方法,比如 WebView 中的 loadUrl 方法;
      3、通过DNS解析获取网址的IP地址,设置 UA 等信息发出第二个GET请求;
  	4、进行HTTP协议会话,客户端发送报头(请求报头);
      5、进入到web服务器上的 Web Server,如 Apache、Tomcat、Node.JS 等服务器;
      6、进入部署好的后端应用,如 PHP、Java、JavaScript、Python 等,找到对应的请求处理;
  	7、处理结束回馈报头,此处如果浏览器访问过,缓存上有对应资源,会与服务器最后修改时间对比,一致则返回304;
      8、浏览器开始下载html文档(响应报头,状态码200),同时使用缓存;
      9、文档树建立,根据标记请求所需指定MIME类型的文件(比如css、js),同时设置了cookie;
      10、页面开始渲染DOM,JS根据DOM API操作DOM,执行事件绑定等,页面显示完成。

    简洁版:
  	浏览器根据请求的URL交给DNS域名解析,找到真实IP,向服务器发起请求;
  	服务器交给后台处理完成后返回数据,浏览器接收文件(HTML、JS、CSS、图象等);
  	浏览器对加载到的资源(HTML、JS、CSS等)进行语法解析,建立相应的内部数据结构(如HTML的DOM);
  	载入解析到的资源文件,渲染页面,完成。

React Native集成友盟推送

公司项目中有推送这个功能。选取了多家,最终还是选择了友盟,虽然友盟官方已经有对React Native支持,但并没有那么完善,因此可能会有一些原生ios代码的改动。原生大神务喷,小白进。

微信小程序中的坑

Canvas


设置粗体时真机不显示,设置 style 才可以在真机显示粗体

ctx.font = "normal bold 18px arial,sans-serif";

真机上无法显示网络图片,只有先下载到本地,才能在真机显示,有两种方法,分别列出

  1. wx.downloadFile,具体请看官方文档
wx.downloadFile({
  url: "https://example.com/audio/123", // 仅为示例,并非真实的资源
  success(res) {
    // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下        载到了想要的内容
    if (res.statusCode === 200) {
      wx.playVoice({
        filePath: res.tempFilePath
      });
    }
  }
});

2.wx.getImageInfo,具体请看官方文档

wx.getImageInfo({
  src: "https://example.com/audio/123", //仅为示例,并非真实的资源
  success(res) {
    console.log(res.path); // 获取图片地址
    console.log(res.width);
    console.log(res.height);
  }
});

原生组件层级


在微信小程序中原生组件的层级最高,所有在怎么设置 z-index 也没什么卵用,但微信官方给了cover-view组件,可覆盖原生组件。

scroll-view 无法设置横向滚动

这个坑呢,我是在 mpvue 中使用的时候遇到的,后来被这个问题弄得头大,也是在 mpvue 中的 issues 中找到解决办法的,具体怎么解决,我就不放代码了,直接放链接吧!!!

解决办法:

mpvue 使用小程序的 scroll-view 横向不能滚动

高适应性的自定义导航栏开发思路

一、默认导航栏计算高度

  • wx.getSystemInfowx.getSystemInfoSync 获取机器信息
  • screenHeight - windowHeight 计算标题栏高度
    'iPhone':64,
    'iPhoneX':88,
    'android':68
  • 不完全统计(ip6 , ip5 , ip6p , ipx , 小米 mix2 , 小米 5 等综合了开发工具提供的数据和真机数据)所得

二、自定义导航栏高度由谁决定?(自定义情况下,屏幕高度和窗口高度没有差别,所以要通过步骤 1 先获取数据,预定义到代码中)

  • 开发时发现,自定义导航栏的实现需要 包含状态栏+胶囊 :没有自定义导航栏的时候页面是全屏幕滚动会出现在状态栏的下一层

  • 根据上一标题中步骤 1 的函数,可以获得状态栏高度 statusBarHeight

  • demo, 点击打开小程序工具

JavaScript闭包的理解

什么是闭包(Closure)

简单讲,闭包就是指有权访问另一个函数作用域中的变量的函数。

**MDN 上面这么说:闭包是一种特殊的对象。**它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。

作用域

�要理解闭包,就得理解Javascript函数作用域。
作用域无非就两种:全局作用域和局部作用域
看下面一个例子

    var a = 2 // 全局作用域
    function foo(){
        var a = 3 // 局部作用域
        console.log(a) // 使用局部作用域中的变量 a,则输出2
    }
    foo()
    console.log(a) // 使用全局作用域中变量 a,则输出3

根据作用域的规则,引擎会从当前执行的作用域开始查找变量,如果找到,则使用该变量,如果找不到,就向上一级继续查找,直到抵达最外层的全局作用域时,无论找到
还是没找到,查找的过程都会停止。

    var a = 2
    function foo(){
        console.log(a) //使用全局作用域中的变量 a,所以输出的是2
    }
    function foo(){
        var a = 2
    }
    console.log(a) //无法访问foo()作用域中定义的量变a,全局作用域又未定义变量,因此输出的是ReferenceError: a is not defined

变量 a 在全局作用域下定义,则全局作用域下的局部作用域内的执行代码或者说是表达式都可以访问到变量 a 的值。局部变量里的同名变量(a)会截断对全局变量 a 的访问,因此在调用函数 foo()时会输出2。JavaScript作用域限制了普通方法是无法让外层作用域访问到内部作用域,因此在全局中输出变量a会是3。

    var a = 2 // 全局作用域
    function foo1(){
        var a = 3 // 局部作用域
        function foo2(){
            console.log(a) //使用的是 foo 的局部变量,所以输出的是3
        }
        return foo2
    }

    var result = foo1()

    result() //输出的是3

闭包是如何产生的?

实际上,上一节代码中的 foo1函数,就是闭包。
简单来讲,当函数外部能访问函数内部时,产生的就是闭包。我理解的是,闭包就是能在全局作用域调用局部作用域,所以闭包就是将函数外部和函数内部连接起来的一座桥梁。

闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
在正常情况下,我们在外部时无法修改函数内部变量的值:

    function print(x) {
    var _internal = 1;

    console.log(_internal + 1);
    }

    print(1); // 2
    // ...
    print(1); // 2

我们可以看的,无论print()调用多少次,输出的值都是2,_internal的值是1

这是因为 JavaScript 中的垃圾回收机制,在多次调用 print() 时,每一次都需要回收前一次的内存,之后再次申请新内存,因此 _internal 无法在内存中继续保存。

那我们如何保存值,那就是使用---闭包

    var add 
    function print() {
        var _internal = 1;

        add = function(x) {
            _internal += x;
        }

        return function log() {
            console.log(_internal);
        }
    }

    var test = print();
    test(); // 1
    add(1);
    test(); // 2

经过上述可以看出,函数 print() 在经过 add() 运行之后,_internal 的值分别为 1 和 2,这就说明了 _internal 始终保存在内存中,并没有在 var test = print(); 调用时被回收。

这是因为 print() 内的 log() 作为返回值,被赋给 test 这个全局变量,因此 log() 始终在内存中。而 log() 依赖 print() 并且可以访问 _internal,所以 print() 也始终在内存中,而且在 var test = print(); 调用时没有被回收。

换而言之,当 _internal 在声明的时候分配了内存,我们可以将其内存地址表示为 0x...1,在 print() 函数被调用之后应该会被回收,但是由于上述原因,没有被回收,它的值将继续保留在地址为 0x...1 中。在外部可以使用指针去寻址,并取得其值。

闭包的弊端

  • 内存泄漏:由于闭包会使得函数内部的变量都被保存在内存中,不会被销毁,内存消耗很大。因此需要在退出函数之前,将不使用的变量都删除。

  • 会修改函数内部变量的值。

参考链接

学习Javascript闭包(Closure)
理解闭包
讲清楚之javascript作用域

在React Native项目中使用fastlane打包apk以及ipa

开发过程中经常遇到多个环境切换的问题,手动切换比较麻烦,使用 fastlane 可以快速切换到不同的 env,打包发布的时候可以有时间来上一杯 ☕️,解放这无处安放的 👋

TOC

安装 fastlane

这里来一个完整版的、最近折腾出现了好多问题

  • 安装最新的Xcode命令行工具
xcode-select --install
  • 完成后加入到环境变量,对应自己的 shell,我这里用了 zsh
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
  • 安装 ruby

rbenv install 2.6.0

  • 检查已安装版本
curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor | bash

output

Checking for `rbenv' in PATH: /usr/local/bin/rbenv
Checking for rbenv shims in PATH: OK
Checking `rbenv install' support: /usr/local/bin/rbenv-install (ruby-build 20181225)
Counting installed Ruby versions: 1 versions
Checking RubyGems settings: OK
Auditing installed plugins: OK 

  • 激活 shell 全局使用的 ruby 版本 rbenv global 2.6.0 关闭 terminal 重新打开就可以正常使用了

  • 安装 fastlane、bundle、cocoapods


gem install bundler

gem install cocoapods

新项目使用fastlane

  • 项目根目录执行 fastlane init,根据提示,做相应的操作。

  • 初始化完成后,fastlane会自动创建fastlane文件夹,文件夹有两个文件FastlaneAppfileAppFile主要是给ios配置AppleId,teamID等,如果只打包安卓的话,可以不用管。

    ![image-20200518182022883](/Users/zhaolinyang/Library/Application Support/typora-user-images/image-20200518182022883.png)

多环境

需要用到react-native-conifg,这个就不讲了,请自行看管方文档

fastlane代码编写

#### 安卓

platform :android do 

  desc "打包安卓测试版本并且上传蒲公英"
  lane :beta do
    gradle(
      task: "clean",
      project_dir:"android/"
    )
    gradle(
      task: 'assembleReleaseTest',
      project_dir:"android/",
      system_properties:{
        "ENVFILE":"" // 找到根目录下的变量文件
      }
    )
    pgyer(api_key: "", user_key: "",password:"123456",install_type:"2") // 打包成功后,自动上传蒲公英
    notification(subtitle: "打包成功!", message: "安卓测试环境打包成功!") // 桌面通知
  end
    
  desc "打包安卓正式版"
  lane :prod do
    gradle(
      task: "clean assemble", 
      build_type: 'Release',
      project_dir:"android/",
      system_properties:{
      	"ENVFILE":"" // 找到根目录下的变量文件
    	}
    )
    pgyer(api_key: "", user_key: "",password:"123456",install_type:"2")
    notification(subtitle: "打包成功!", message: "安卓打包成功!")
  end
end

ios

platform :ios do
  desc '打包ios测试环境'
  lane :beta_to_firim do
    scheme = "more_app_rn"
    date = Time.new.strftime("%Y%m%d-%h%M")

    get_push_certificate(
      website_push:true
    )
    
    # 自动打ad_hoc测试包
    gym(
      # 指定 workspace, 这个参数很重要,否则你还需要手动选择一次打包对象
      workspace:"ios/more_app_rn.xcworkspace",
      # 指定scheme
      scheme:"#{scheme}",
      # 打包后的 ipa 名称
      output_name:"#{scheme}-#{date}.ipa",
      # 是否在运行时自动清理上一次的执行
      clean:true,
      # 签名
      export_options:{
        provisioningProfiles:{
          "包名" => "证书"
        }
      },
      # 指定要打包的配置名
      configuration:"Release",
      # 指定打包所使用的输出方式,目前支持 app-store, package, ad-hoc, enterprise, development,  developer-id,即 xcodebuild  method 参数
      export_method:"ad-hoc",
      # 最后输出的文件夹路径
      output_directory:"./fastlane/build",
    )

    puts "开始上传蒲公英"
    
    pgyer(api_key: "", user_key: "", password: "123456", install_type: "2")

    notification(subtitle: "打包成功!", message: "ios测试环境打包成功!")
  end

  desc '打包ios正式环境并且上传app_store'
  lane :upload_app_store do
    scheme = "包名(pord)"
    date = Time.new.strftime("%Y%m%d-%h%M")

     # 自动打ad_hoc测试包
     gym(
      # 指定 workspace, 这个参数很重要,否则你还需要手动选择一次打包对象
      workspace:"ios/包名.xcworkspace",
      # 指定scheme
      scheme:"#{scheme}",
      # 打包后的 ipa 名称
      output_name:"#{scheme}-#{date}.ipa",
      # 是否在运行时自动清理上一次的执行
      clean:true,
      # 签名
      export_options:{
        provisioningProfiles:{
          "包名" => "证书"
        }
      },
      # 指定要打包的配置名
      configuration:"Release",
      # 指定打包所使用的输出方式,目前支持 app-store, package, ad-hoc, enterprise, development,  developer-id,即 xcodebuild  method 参数
      export_method:"app-store",
      # 最后输出的文件夹路径
      output_directory:"./fastlane/build",
    )

    # deliver(
    #   #注意:submit_for_review这个true是提交审核,false不提交
    #   # skip_binary_upload: true,
    #   submit_for_review: false,
    # )
    # notification(subtitle: "打包成功!", message: "ios打包成功,并且上传成功!")
  end
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.