Smilebuling

Smilebuling 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑

前端小白

个人动态

Smilebuling 收藏了文章 · 2018-08-06

vuex文档笔记

vuex采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。每个应用将仅仅包含一个 store 实例。Vuex 通过 store选项,提供了一种机制将状态从根组件『注入』到每一个子组件中(需调用 Vue.use(Vuex))。

五个核心概念

  1. State: state为store中的最基本的状态。
    既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:
    最好提前在你的 store 中初始化好所有所需属性。当需要在对象上添加新属性时,你应该
    使用 Vue.set(obj, 'newProp', 123), 或者以新对象替换老对象。例如,利用 stage-3 的对象展开运算符我们可以这样写:state.obj = { ...state.obj, newProp: 123 }

    Vue.set(obj, 'newProp', 123)
    state.obj = { ...state.obj, newProp: 123 }
  2. Getter:getters为从state中派生出的一些状态,相当于state的计算属性。当getter所依赖的state值发生变化时,getters会被重新计算。getters接受store作为第一个参数,暴露为store.getters。getters还可以接受其他getters作为第二个参数。
  3. Mutations:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutations 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。mutation虽然类似于一个事件,但是不能直接调用,要通过store.commit('increment')的方式触发。你可以向 store.commit 传入额外的参数。
    mutation 必须是同步函数
    你可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。
  4. Action:因为mutation为同步函数而存在。so Action是可以包含任何异步操作的。但是要记住Action提交的是mutation而不是直接改变state。Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
查看原文

Smilebuling 赞了文章 · 2018-07-25

前端的一些坑,一些记录,一些冷知识

无限期更新前端的一些坑,一些记录,一些冷知识
https://github.com/ssshooter/...

大概从 17 年的六月份开始记录吧,也已经一年了,其中也包含了一些很简单的知识,以前还觉得挺难的,现在看起来有点谜之感慨...

JavaScript

  • 所有对象都有 __proto__ 属性,都指向创造对象的函数对象的 prototype
  • 上传文件要使用 formdata 包装。
  • Promise.prototype.catch 方法是 .then(null, rejection) 的别名。
  • 同一个 EventTarget 注册了多个相同的 EventListener,那么重复的实例会被抛弃。所以这么做不会使得 EventListener 被调用两次,也不需要用 removeEventListener 手动清除多余的EventListener,因为重复的都被自动抛弃了。
  • 当使用 addEventListener() 为一个元素注册事件的时候,句柄里的 this 值是该元素的引用。其与传递给句柄的 event 参数的 currentTarget 属性的值一样,而 target 是直接接受事件的子元素。
  • scrollIntoView() 使 div 底部滚动到视窗。
  • 使用 const 的对象和数组的内容是可以被修改的,但数据结构不可变。
  • 在 webpack 里,所有的文件都是模块。loader 的作用就是把文件转换成 webpack 可以识别的模块。
  • 关于事件循环,执行下一个 task 之前总会清空 microtask。
  • npm 新旧版本覆盖可能会造成迷之问题,这个时候可以试试 node_module 整个删掉重装。
  • *、/ 和 - 操作符都是数字运算专用的。当这些运算符与字符串一起使用时,会强制转换字符串为数字类型的值。
  • document.title 可以直接修改当前 html 的标题。
  • 利用对象浅拷贝修改对象,指向同一对象的两个变量修改对象的效果一样。
  • 脑洞题:1 和 2 只用一次的情况下怎么得到 4 答案:1<<2。
  • 连等赋值从右到左。
  • compositionstart 事件触发于一段文字的输入之前(类似于 keydown 事件,但是该事件仅在若干可见字符的输入之前,而这些可见字符的输入可能需要一连串的键盘操作、语音识别或者点击输入法的备选词)。
  • void 0(void后面加任何东西)用于生成一个绝对的 undefined(不会被重定义),但跟函数会有副作用
  • 注意 localStorage 保存的只能是字符串,所以是没有 null 的。
  • 坑一个

    typeof [] === 'object' // true
    typeof null === 'object' // true
  • import 同步,require异步(待补充)
  • new() 做了些什么?

    var obj = new Base();
    var obj  = {};
    obj.__proto__ = Base.prototype;
    Base.call(obj);
  • stage 0 到 4 的含义:

    stage 0 is "i've got a crazy idea",
    stage 1 is "this idea might not be stupid",
    stage 2 is "let's use polyfills and transpilers to play with it",
    stage 3 is "let's let browsers implement it and see how it goes",
    stage 4 is "now it's javascript".
  • Object.getOwnPropertyNames(obj).length === 0 判断 obj 是不是空对象。
  • getBoundingClientRect() 用于获取元素宽高以及距离页面边框距离,十分方便。
  • && 的使用场景:左边为真继续执行右边,如 isDog && bark()
  • || 的使用场景:左边为假继续执行右边,如 let i = value || defalutValue

Vue.js

  • v-model 会自动 bind 一个值,其变量名为 value。
  • 多个特性的元素应该分多行撰写,每个特性一行。以下为 vscode 里 vetur 的设置:

    "vetur.format.defaultFormatterOptions": {
        "js-beautify-html": {
          "wrap_attributes": "force" 
        }
      }
  • 组件 destroy 时触发自定义指令的 unbind,destory 的时机:diff 之后的 patch,如 v-if,v-for(key不同时,先销毁原来的,再挂载新的(推测))
  • 自定义组件 v-model watch 自动匹配(存疑
  • 组件的 data 属性要用函数返回的原因:创建实例时如果 data 是一个对象的话,所有实例都会引用同一个对象,而对象返回不会有此问题。在浏览器中可以这么做是因为根实例只有一个。
  • .vue 文件中使用 /deep/ 覆盖子组件 css

GitHub

  • 从 commit 关闭 issues 的方法:commit 信息写 Fixes #33,其他关键字还有 close closes closed fix fixes fixed resolve resolves resolved
  • git reset --soft HEAD^ 回退一次 commit

CSS

  • div 的默认宽度是父元素宽的 100%
  • 逐帧动画 animation: animate-name 3s steps(每次循环的帧数) infinite;

    @keyframes animate-name{
        from{
        <!--原位-->
            background-position: 0 0; 
        }
        to{
        <!--最后一帧-->
            background-position: -1540px 0 ;
        }
    }
  • "Break out" of a parent's containing width to take the full screen of a page w/this nice utility class:

    .full-width {
      width: 100vw;
      position: relative;
      left: 50%;
      right: 50%;
      margin-left: -50vw;
      margin-right: -50vw;
    }
  • 行内元素与下一个元素中间有空格(正常排版),会引起一些诡异的缝隙,常见的例如元素之间有间隔,或看起来空了一行(像加了padding)
  • pre 标签设置自动换行 white-space: pre-wrap;
  • 隐藏一个元素,同时让这个元素的宽度可获取:设置 overflow: hidden 可以根据元素高度裁剪视区,设置 height: 0; overflow: hidden 虽然文档流中占用了位置,由于高度为 0,最终表现特征达到了我们期望的 display: none。此时该元素 clientHeightoffsetHeight 为 0,但是 scrollHeight 是有值的。scrollHeight 是一个元素没有滚动条时的所有内容高度,当一个元素没有滚动条时 scrollHeight === offsetHeight
  • 当 Render Tree 中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
  • 当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
  • 回流必将引起重绘,重绘不一定会引起回流。
  • 移动端优化常用 CSS 属性:

    user-select: none; // 禁止文字被选中
    outline:none; // 去除点击外边框,点击无轮廓
    -webkit-touch-callout: none; // 长按链接不弹出菜单
    -webkit-tap-highlight-color: rgba(0,0,0,0); // 去除点击高亮
  • @keyframes 的属性要前后对应,否则不形成动画
  • img 元素图像自适应居中,与 background-size 效果一样

    object-fit: cover; 
  • <img /> 标签千万记得写宽高,不然会花式塌陷
  • flex-grow 所在元素如果未定宽度的话,宽度会被子元素撑开
  • 一个英文单词默认不换行,无论多长,所以要设置 word break
  • 多行文字居中

    .mulit_line{ 
        border:1px dashed #cccccc; 
        padding-left:5px;
    }
    .mulit_line span{ 
        display:inline-block; 
        line-height:14px; 
        vertical-align:middle;
    }
  • safari 中控制惯性滚动 -webkit-overflow-scroll
  • 滚动条样式可能使滚动条强制显示(未确定)
  • flex 布局不换行加 flex-shrink: 0; 实现 div 不压缩无限并排,可以用于 swiper 等场景。
  • 巧用猫头鹰选择器 +
  • float 自带 display: inline-block
  • 鼠标禁用 .disabled { pointer-events: none; }
  • 注意 :last-child 与 :last-of-type 的区别
  • ::after 表示法是在 CSS3 中引入的,:: 符号是用来区分伪类和伪元素的。支持CSS3的浏览器同时也都支持 CSS2 中引入的表示法 :after。
  • 父元素如果存在 transform 属性,子元素的 position: fixed 属性无效
  • less 中的 calc 问题:height: calc(~"100% - 50px");
  • vh 在部分浏览器中包含地址栏部分,小心使用。

VSCode

  • alt + shift + 鼠标点击 纵向选择
  • vetur 分号问题: 安装 prettier,然后配置 "prettier.singleQuote":true,"prettier.semi": false
  • 可以使用插件 document this 方便写注释
  • html tag 属性分行 wrap_attributes:force
  • 选定变量后按 F12 找到定义位置

其他

  • 魔法隧道用 webpack 代理会 502
  • 在组件化编程中,悼念被同名组件浪费了几个钟的 debug 时间[蜡烛]
  • 局域网连不通的话,先试试,开共享,关闭防火墙
  • 局域网连不通的话,还可以试试,在 webpack.config.js 文件的 devServer 里加上host:'0.0.0.0'
  • iOS 的回弹效果,动的是 body 部分,html 是不动的
  • 学习一个语言之前先看规范
  • safari 的 formdata 只支持 append,其他方法需要 polyfill
  • rc 的意思是 run commands
  • 导航栏高度 88px,标签栏高度 98px(iphone5和6常用)
  • 关于 HTTP 304 Not Modified,简单来说,请求内容没有发生变化的时候,根据设置,服务器可能直接取缓存返回
查看原文

赞 173 收藏 123 评论 10

Smilebuling 赞了文章 · 2018-07-25

如何实现一个HTTP请求库——axios源码阅读与分析

概述

在前端开发过程中,我们经常会遇到需要发送异步请求的情况。而使用一个功能齐全,接口完善的HTTP请求库,能够在很大程度上减少我们的开发成本,提高我们的开发效率。

axios是一个在近些年来非常火的一个HTTP请求库,目前在GitHub中已经拥有了超过40K的star,受到了各位大佬的推荐。

今天,我们就来看下,axios到底是如何设计的,其中又有哪些值得我们学习的地方。我在写这边文章时,axios的版本为0.18.0。我们就以这个版本的代码为例,来进行具体的源码阅读和分析。当前axios所有源码文件都在lib文件夹中,因此我们下文中提到的路径均是指lib文件夹中的路径。

本文的主要内容有:

  • 如何使用axios
  • axios的核心模块是如何设计与实现的(请求、拦截器、撤回)
  • axios的设计有什么值得借鉴的地方

如何使用axios

想要了解axios的设计,我们首先需要来看下axios是如何使用的。我们通过一个简单示例来介绍以下axios的API。

发送请求

axios({
  method:'get',
  url:'http://bit.ly/2mTM3nY',
  responseType:'stream'
})
  .then(function(response) {
  response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});

这是一个官方的API示例。从上面的代码中我们可以看到,axios的用法与jQuery的ajax很相似,都是通过返回一个Promise(也可以通过success的callback,不过建议使用Promise或者await)来继续后面的操作。

这个代码示例很简单,我就不过多赘述了,下面让我们来看下如何添加一个过滤器函数。

增加拦截器(Interceptors)函数

// 增加一个请求拦截器,注意是2个函数,一个处理成功,一个处理失败,后面会说明这种情况的原因
axios.interceptors.request.use(function (config) {
    // 请求发送前处理
    return config;
  }, function (error) {
    // 请求错误后处理
    return Promise.reject(error);
  });

// 增加一个响应拦截器
axios.interceptors.response.use(function (response) {
    // 针对响应数据进行处理
    return response;
  }, function (error) {
    // 响应错误后处理
    return Promise.reject(error);
  });

通过上面的示例我们可以知道:在请求发送前,我们可以针对请求的config参数进行数据处理;而在请求响应后,我们也能针对返回的数据进行特定的操作。同时,在请求失败和响应失败时,我们都可以进行特定的错误处理。

取消HTTP请求

在完成搜索相关的功能时,我们经常会需要频繁的发送请求来进行数据查询的情况。通常来说,我们在下一次请求发送时,就需要取消上一次请求。因此,取消请求相关的功能也是一个优点。axios取消请求的示例代码如下:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');

通过上面的示例我们可以看到,axios使用的是基于CancelToken的一个撤回提案。不过,目前该提案已经被撤回,具体详情可以见此处。具体的撤回实现方法我们会在后面的章节源码分析的时候进行说明。

axios的核心模块是如何设计与实现的

通过上面的例子,我相信大家对axios的使用方法都有了一个大致的了解。下面,我们将按照模块来对axios的设计与实现进行分析。下图是我们在这篇博客中将会涉及到的相关的axios的文件,如果读者有兴趣的话,可以通过clone相关代码结合博客进行阅读,这样能够加深对相关模块的理解。

HTTP请求模块

作为核心模块,axios发送请求相关的代码位于core/dispatchReqeust.js文件中。由于篇幅有限,下面我选取部分重点的源码进行简单的介绍:

module.exports = function dispatchRequest(config) {
    throwIfCancellationRequested(config);

    // 其他源码

    // default adapter是一个可以判断当前环境来选择使用Node还是XHR进行请求发送的模块
    var adapter = config.adapter || defaults.adapter; 

    return adapter(config).then(function onAdapterResolution(response) {
        throwIfCancellationRequested(config);

        // 其他源码

        return response;
    }, function onAdapterRejection(reason) {
        if (!isCancel(reason)) {
            throwIfCancellationRequested(config);

            // 其他源码

            return Promise.reject(reason);
        });
};

通过上面的代码和示例我们可以知道,dispatchRequest方法是通过获取config.adapter来得到发送请求的模块的,我们自己也可以通过传入符合规范的adapter函数来替换掉原生的模块(虽然一般不会这么做,不过也算是一个松耦合扩展点)。

default.js文件中,我们能够看到相关的adapter选择逻辑,即根据当前容器中特有的一些属性和构造函数来进行判断。

function getDefaultAdapter() {
    var adapter;
    // 只有Node.js才有变量类型为process的类
    if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
        // Node.js请求模块
        adapter = require('./adapters/http');
    } else if (typeof XMLHttpRequest !== 'undefined') {
        // 浏览器请求模块
        adapter = require('./adapters/xhr');
    }
    return adapter;
}

axios中XHR模块较为简单,为XMLHTTPRequest对象的封装,我们在这里就不过多进行介绍了,有兴趣的同学可以自行阅读,代码位于adapters/xhr.js文件中。

拦截器模块

了解了dispatchRequest实现的HTTP请求发送模块,我们来看下axios是如何处理请求和响应拦截函数的。让我们看下axios中请求的统一入口request函数。

Axios.prototype.request = function request(config) {

    // 其他代码

    var chain = [dispatchRequest, undefined];
    var promise = Promise.resolve(config);

    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
        chain.unshift(interceptor.fulfilled, interceptor.rejected);
    });

    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
        chain.push(interceptor.fulfilled, interceptor.rejected);
    });

    while (chain.length) {
        promise = promise.then(chain.shift(), chain.shift());
    }

    return promise;
};

这个函数是axios发送请求的入口,因为函数实现比较长,我就简单说一下相关的设计思路:

  1. chain是一个执行队列。这个队列的初始值,是一个带有config参数的Promise。
  2. 在chain执行队列中,插入了初始的发送请求的函数dispatchReqeust和与之对应的undefined。后面需要增加一个undefined是因为在Promise中,需要一个success和一个fail的回调函数,这个从代码promise = promise.then(chain.shift(), chain.shift());就能够看出来。因此,dispatchReqeustundefined我们可以成为一对函数。
  3. 在chain执行队列中,发送请求的函数dispatchReqeust是处于中间的位置。它的前面是请求拦截器,通过unshift方法放入;它的后面是响应拦截器,通过push放入。要注意的是,这些函数都是成对的放入,也就是一次放入两个。

通过上面的request代码,我们大致知道了拦截器的使用方法。接下来,我们来看下如何取消一个HTTP请求。

取消请求模块

取消请求相关的模块在Cancel/文件夹中。让我们来看下相关的重点代码。

首先,让我们来看下元数据Cancel类。它是用来记录取消状态一个类,具体代码如下:

    function Cancel(message) {
      this.message = message;
    }

    Cancel.prototype.toString = function toString() {
      return 'Cancel' + (this.message ? ': ' + this.message : '');
    };

    Cancel.prototype.__CANCEL__ = true;

而在CancelToken类中,它通过传递一个Promise的方法来实现了HTTP请求取消,然我们看下具体的代码:

function CancelToken(executor) {
    if (typeof executor !== 'function') {
        throw new TypeError('executor must be a function.');
    }

    var resolvePromise;
    this.promise = new Promise(function promiseExecutor(resolve) {
        resolvePromise = resolve;
    });

    var token = this;
    executor(function cancel(message) {
        if (token.reason) {
            // Cancellation has already been requested
            return;
        }

        token.reason = new Cancel(message);
        resolvePromise(token.reason);
    });
}

CancelToken.source = function source() {
    var cancel;
    var token = new CancelToken(function executor(c) {
        cancel = c;
    });
    return {
        token: token,
        cancel: cancel
    };
};

而在adapter/xhr.js文件中,有与之相对应的取消请求的代码:

if (config.cancelToken) {
    // 等待取消
    config.cancelToken.promise.then(function onCanceled(cancel) {
        if (!request) {
            return;
        }

        request.abort();
        reject(cancel);
        // 重置请求
        request = null;
    });
}

结合上面的取消HTTP请求的示例和这些代码,我们来简单说下相关的实现逻辑:

  1. 在可能需要取消的请求中,我们初始化时调用了source方法,这个方法返回了一个CancelToken类的实例A和一个函数cancel。
  2. 在source方法返回实例A中,初始化了一个在pending状态的promise。我们将整个实例A传递给axios后,这个promise被用于做取消请求的触发器。
  3. 当source方法返回的cancel方法被调用时,实例A中的promise状态由pending变成了fulfilled,立刻触发了then的回调函数,从而触发了axios的取消逻辑——request.abort()

axios的设计有什么值得借鉴的地方

发送请求函数的处理逻辑

在之前的章节中有提到过,axios在处理发送请求的dispatchRequest函数时,没有当做一个特殊的函数来对待,而是采用一视同仁的方法,将其放在队列的中间位置,从而保证了队列处理的一致性,提高了代码的可阅读性。

Adapter的处理逻辑

在adapter的处理逻辑中,axios没有把http和xhr两个模块(一个用于Node.js发送请求,另一个则用于浏览器端发送请求)当成自身的模块直接在dispatchRequest中直接饮用,而是通过配置的方法在default.js文件中进行默认引入。这样既保证了两个模块间的低耦合性,同时又能够为今后用户需要自定义请求发送模块保留了余地。

取消HTTP请求的处理逻辑

在取消HTTP请求的逻辑中,axios巧妙的使用了一个Promise来作为触发器,将resolve函数通过callback中参数的形式传递到了外部。这样既能够保证内部逻辑的连贯性,也能够保证在需要进行取消请求时,不需要直接进行相关类的示例数据改动,最大程度上避免了侵入其他的模块。

总结

本文对axios相关的使用方式、设计思路和实现方法进行了详细的介绍。读者能够通过上述文章,了解axios的设计思想,同时能够在axios的代码中,学习到关于模块封装和交互等相关的经验。

由于篇幅原因,本文仅针对axios的核心模块进行了分解和介绍,如果对其他代码有兴趣的同学,可以去GitHub进行查看。

如果有任何疑问或者观点,欢迎随时留言讨论。

查看原文

赞 185 收藏 140 评论 0

Smilebuling 关注了标签 · 2018-06-20

iview

iView iViewNPM downloadsJoin the chat at https://gitter.im/iview/iview

A high quality UI Toolkit built on Vue.js.

This branch is for Vue.js 2.x

HERE is for Vue.js 1.x

Docs

中文文档 (2.0)

中文文档 (1.0)

English (2.0)(Working)

Overview

组件概览(Component Overview)

Features

  • High quality and rich functions

  • Friendly APIs,free and flexible

  • Great Documentation

  • It is quite beautiful

  • Support Vue.js 2 and Vue.js 1

  • Based on npm + webpack + babel, using ES2015

Programming

iView

Install

Install vue-webpack project in the first place

Use iview-project(Recommended) Or vue-cli

Install iView

using npm

npm install iview --save

Or using script tag for global use

<script type="text/javascript" data-original="iview.min.js"></script>

Usage

<template>
    <Slider v-model="value" range></Slider>
</template>
<script>
    export default {
        data () {
            return {
                value: [20, 50]
            }
        }
    }
</script>

Use css

import 'iview/dist/styles/iview.css';

Browser Support

Normal browsers and Internet Explorer 9+.

Major Contributors

NameAvatar
Aresn
jingsam
rijn
GITleonine1989
huixisheng

Links

License

MIT

Copyright (c) 2016-present, iView

关注 428

Smilebuling 关注了用户 · 2018-01-30

曾经是男神经病 @moedesu

关注 1

Smilebuling 赞了文章 · 2017-09-29

call, apply, bind 函数能干啥?如何在日常搬砖中使用?(全)

call(),apply(),bind() 函数大家可能都有所了解,但是在平时搬砖过程中很可能或者基本没用过,学过但都淡忘了。

但是在大量第三方的框架(库),甚至js自己都在 源码中大量使用call,apply 函数。所以今天和大家仔细讨论下它们在 开发中的应用场景

1 . 它们是啥意思

1.1 作用

  1. 他们的作用都是改变函数内部的this
  2. 这三个函数都是函数对象的方法,也就是说只有函数才可以直接调用这些方法。

ps:call,apply,bing属于this显示绑定,还有好几种其他的this绑定方式,感兴趣的可以点这里

1.2 三者区别

  • 参数: 三个函数的第一个参数都是需要绑定的 this

call: 可以有n个参数,从第二个参数开始的所有参数都是原函数的参数。

`apply`:只有两个参数,并且第二个参数必须为数组,数组中的所有元素一一对应原函数的参数。

`bind`: 只有一个参数,即要绑定的this。

    call 语法:  foo.call(this, arg1,arg2, ... ,argn );
    apply 语法: foo.apply(this, [ arg1,arg2, ... ,argn ] );
    bind 语法:  foo.bind(this);
  • 调用:

call,apply: 调用后立即执行原函数。

`bind`: 调用后返回已经绑定好this的函数。

小例子一枚:


    function foo(a,b){
        console.log(a+b);
    }
    foo.call(null,'海洋','饼干');        // 海洋饼干  这里this指向不重要就写null了
    foo.apply(null, ['海洋','饼干'] );   // 海洋饼干
    var fun = foo.bind(null);
    fun('海洋','饼干');                  // 海洋饼干

2 .它们能干啥事

这是我们今天讨论的主题,这三个函数如何应用?什么情况下使用?能改变this指向又能咋滴?

2 .1 处理伪数组 (最常用)

先考虑一个问题,如果你使用var arr = document.getElementsByTagName('li')获取了5个li元素,你现在需要获取其中的第2,3,4三个元素,你会怎么做?

这样arr.slice(1,4);? 啊哦,TypeError -- arr.slice is not a function(slice不是函数),数组操作在日常搬砖中非常常见,我见过最傻的解决这个问题的方式是使用循环,将需要的元素一个个添加到一个新数组里0.0,下面我介绍的方法完全可以在实战中使用,可以给你的代码加分哦,非常方便简洁(中高级前端程序员中,算是基本操作了)。

先要介绍一个概念( 伪数组 ),这也是为什么我们刚刚slice切割数组时出错的原因: (对新手来说算是干货了,知道的可以跳过)

什么是伪数组?( 字面的意思已经呼之欲出了 )

  1. 有length属性
  2. 能按索引存储数据
  3. 能像遍历数组一样来遍历
  4. 不能使用数组的push()、slice()等方法

简单来说就是可以像数组一样操作的对象,但是没有数组的方法。

js中存在大量伪数组,如 :

1. function的arguments对象。
2. getElementsByName(),getElementsByTagName(),childNodes/children 等方法的返回值。
3. 还有比较常见的jquery,使用它获取的元素也是伪数组。

回到原来的问题,如何截取伪数组中的元素:伪数组没有这些方法,我们'借用'Array的slice不就行了

[].slice.call(arr,1,4);  // 推荐写法

不想借用你可以直接给伪数组添加一个slice函数,如

arr.slice = [].slice;
arr.slice(1,4);

当然,'借用' 更方便,直接添加会导致伪数组对象'污染'。

如果可以随意改变原对象,可以 直接将其转成真正的数组对象

[].slice.call(arr);

2 .2 继承

继承方式多种多样,我们现在讨论的这种是其中很重要的一种实现方式,用call实现 js 构造函数继承

  • 单继承
function person(name){
    this.name = name
}
function man(name){
    this.age = '男';
    person.call(this,name);              // 继承 man
}
var me = new man('海洋饼干');

console.log(me.name,me.age);             // '海洋饼干' '男'
  • 多继承
function person(name){
    this.name = name
}
function man(name){
    this.age = '男';
}
function manProgrammer(name){
    this.girlfriend = null;
    person.call(this,name);  // 继承 person
    man.call(this,name);     // 继承 man
}
var me = new manProgrammer('海洋饼干');

console.log(me.name,me.age,me.girlfriend);   // '海洋饼干' '男' null

2 .3 this 硬绑定 --- bind

将一个对象强制且永久性绑定到函数的this上,使用call,apply或者其他的绑定方式都无法改变(除了new绑定,当然,可以手动撸一个new都无法改变的硬绑定)

直接看例子:

var fun ;
var obj = {
    a : 1,
    foo : function(){
        var _this = this;            //平时有没有过这种写法? 为了防止this指向问题
                                     //将this赋值给一个变量,间接维持了this的安全性
       fun = function(){
            console.log(_this.a);
        }
    }
}
obj.foo();
fun();                 // 1

var obj1 = { a : 2}
obj.foo.call(obj1);    // 直接修改_this所绑定的值,boom了
fun();                 // 2

但是这种方法感觉上是在逃避问题,直接不使用this了 ? 这真的不是什么好的解决问题的态度。下面使用我们的bind来优化一下:

var fun ;
var obj = {
    a : 1,
    foo : function(){            // 不使用 _this, 避免无谓的变量声明
        fun = function(){
            console.log(this.a);
        }.bind(this);            // 代码很简洁,很漂亮(b格)
    }
}
var obj1 = { a : 2}
obj.foo();
fun();             // 1
fun.call(obj1);    // 1  call ,apply等绑定 无法修改
                   // 这里和上面call的位置不同是因为this所处于不同的位置

这样替代 _this 很规(zhuang)范(b)

ps:call,apply,bing属于this显示绑定,还有好几种其他的this绑定方式,感兴趣的可以点这里

2 .4 取数组最大最小值

Math.max和min方法,接收多个参数,比较出极值,这里用到apply的一个默认功能:展开数组传入一个数组参数就可以默认将这个数组转成一个个参数的形式赋给原函数

var num = [6,9,-3,-5];
console.log(Math.max.apply(Math,num)); // 9  等价  console.log(Math.max(6,9,-3,-5));
console.log(Math.min.apply(Math,num)); // -5 等价  console.log(Math.min(6,9,-3,-5));

2 .5 合并数组

合并数组常见有三种方式,1.循环 2.Array的concat() 3. 使用apply()合并

这里是使用最简便的apply

var a = [1,2,3];
var b = [4,5,6];
[].push.apply(a,b);    // 借用数组的push方法 等价 a.push(4,5,6);
console.log(a);        // [1, 2, 3, 4, 5, 6]

觉得对你有帮助点个赞呗555

大家有什么实用点的黑科技欢迎私信评论 分享,我会贴上id和你的分享 >_<



ps:这里统一回应一下关于call,bind是不是不常用,是不是被其他方法取代和是不是除了炫技就没用了等说法,如果看过至少一个js框架或者方法库的源码的同学就会发现,源码中最重要的函数和大量地方使用了call,bind,这是一个绕不开的底层的东西,用其他方法或者不用只是暂时的,深入学习js或者自己后面阅读和自己开发js库的时候这是必须使用的入门级知识点,一定程度上决定了天花板的高度。上面的用法只是抛砖引玉,毕竟日常的使用和框架开发是完全不同的领域。

查看原文

赞 58 收藏 262 评论 16

Smilebuling 赞了文章 · 2017-09-27

html简单响应式滚动条置顶

简单响应式滚动条置顶

一般的,让页面出现滚动条的常见方法有:

overflow:auto||overflow:scroll
或者overflow-x水平滚动条和overflow-y垂直滚动条

那么现在要实现这样的一个效果:

直接在body中给一个header,后面一个Group盒子,并且header为常驻顶部的,实现滚动条顶部位置不滚动到header中(包含在header中会影响美观) 

首先看例子:
sfNote_0924_0182b3f.png

分析:

每当滚动条移动到header的高度的位置时,这时盒子中的前排内容是并没有显示出来的,但是滚动条到此处就得停止。那么盒子首先就需要设置一个margin-top:header的高 ,和定位top的值 ,在js中也要控制scrollTop值,通过判断滚动条移动到容器顶部时固定

header{position: fixed;top: 0;left: 0;right: 0;z-index: 999;}  
  #con{margin-top: 150px;position: absolute;top:50px;}

sfNote_0924_038b8df.png

最终效果:

sfNote_0924_04d47fa.png

js获取屏幕滚动条:document.documentElement.scrollTop || document.body.scrollTop
查看原文

赞 3 收藏 5 评论 0

Smilebuling 赞了文章 · 2017-09-27

浏览器滚动条样式还可以改变,你知道吗?

有时候,我们是不是觉得浏览器默认的滚动条很low, 那么浏览器滚动条样式能否改变呢,答案是肯定的,今天就给大家分享一下怎么改变浏览器的默认滚动条,让我们的页面更加炫酷。

在次之前,我们先来了解一下滚动条产生的原因,通俗的来讲就是内容超出容器就会出现滚动条。

verflow介绍

<h5>定义:overflow 属性指定当它溢出其块级容器时,是否剪辑内容,渲染滚动条或显示内容。
属性值

overflow:visible    //默认值。内容不会被修剪,超出内容会显示在元素框之外
overflow:hidden     //内容会被修剪。超出内容被隐藏
overflow:scroll     //内容会被修剪,浏览器会显示滚动条以便查看其余内容
overflow:auto       //如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容
overflow:inherit    //规定从该父元素继承overflow属性的值`

注:任何的版本的 Internet Explorer (包括 IE8)都不支持属性值 “inherit”。
当overflow设为除默认值(visible)以外的值时,将会创建一个会 块级式化上下文 (清除浮动的一种方式),更多可查看深入理解BFC和Margin Collapse

下面直接进入教程,以Google浏览器为例:

效果图:

webkit内核的浏览器滚动条样式

首先给两个div,两个div是父子关系,里面的div宽高比外面的宽高值大,再加上overflow:hidd属性模拟出现滚动条效果,然后进行css更改样式。

html部分

<style>
    #scrollbar {
        width:300px;
        height:300px;
        overflow:auto;
        float: left;
    }
    #scrollbar div {
        width:800px;
        height:2000px;
    }
</style>
<body>
    <div id='scrollbar'>    
        <div ></div>   
    </div>
</body>

css样式

<style>
    #scrollbar::-webkit-scrollbar             {   滚动条整体部分,其中的属性有width,height,background,border(就和一个块级元素一样)等。
        width:12px;
        height:12px;
    }
    #scrollbar::-webkit-scrollbar-button      {   滚动条两端的按钮。可以用display:none让其不显示,也可以添加背景图片,颜色改变显示效果。
        width:12px;
        height:12px;
    }
    #scrollbar::-webkit-scrollbar-track       {   外层轨道。可以用display:none让其不显示,也可以添加背景图片,颜色改变显示效果。
      background: #232428;
      border-radius: 20px;

    }
    #scrollbar::-webkit-scrollbar-track-piece {   内层轨道,滚动条中间部分(除去)。
      background: #232428;
      border-radius: 20px;
    }
    #scrollbar::-webkit-scrollbar-thumb       {   滚动条里面可以拖动的那部分
        background:#85868B;
        border-radius:50px;
    }
    #scrollbar::-webkit-scrollbar-corner      {   边角
        background:#fff;
    }
    #scrollbar::-webkit-scrollbar-resizer     {   定义右下角拖动块的样式
        background:#fff; 
    }
  </style>

这里给大家做了个图,方便大家理解:

自定义IE浏览器滚动条样式

IE浏览器,就比较简单了,直接定义整个页面的滚动条 ,但IE浏览器只能更换颜色不能设置背景颜色。

body {
   scrollbar-arrow-color: #f4ae21;                /*三角箭头的颜色*/

   scrollbar-face-color: #333;                    /*立体滚动条的颜色*/

   scrollbar-3dlight-color: #666;                 /*立体滚动条亮边的颜色*/
 
   scrollbar-highlight-color: #666;               /*滚动条空白部分的颜色*/

   scrollbar-shadow-color: #999;                  /*立体滚动条阴影的颜色*/

   scrollbar-darkshadow-color: #666;              /*立体滚动条强阴影的颜色*/

   scrollbar-track-color: #666;                   /*立体滚动条背景颜色*/

   scrollbar-base-color:#f8f8f8;                  /*滚动条的基本颜色*/

   Cursor:url(mouse.cur);                         /*自定义个性鼠标*/
 }
查看原文

赞 6 收藏 47 评论 4

Smilebuling 赞了文章 · 2017-09-27

Sublime Text 3安装和插件安装,你知道多少呢?

Sublime text 3常用插件安装
话不多说,直接让我们来安装吧!!!

第一步:安装Sublime Text 3。安装网址:http://www.sublimetext.com/3

第二步:使用Package Control组件安装系列插件。

  1. 使用快捷键 Ctrl+` 显示出console.
  2. 粘贴以下代码到底部命令行,回车.

    import urllib.request,os; pf = 'Package Control.sublime-package';
    ipp = sublime.installed_packages_path();urllib.request.install_opener
    ( urllib.request.build_opener( urllib.request.ProxyHandler()) ); open
    (os.path.join(ipp, pf), 'wb').write(urllib.request.urlopen
    ( 'http://sublime.wbond.net/

' + pf.replace(' ','%20')).read())

  1. 重启 Sublime Text 3.
  2. 若在 Preferences 中的 package settings 一项中看到package control 这一项,则表示此项安装成功。

第三步:利用Package Control安装插件方法

  • 使用快捷键 Ctrl+Shift+P 弹出一个命令窗口。
  • 输入install,双击选择Install package选项,然后输入想下载的插件。

接下来,我们就来一个一个安装吧!!!

  1. SublimeTmpl (sublime默认的快捷键)
    Ctrl+Alt+H ——> html

Ctrl+Alt+J ——> javascript
Ctrl+Alt+C ——> css
Ctrl+Alt+P ——> php
Ctrl+Alt+R ——> ruby
Ctrl+Alt+Shift+P ——> python

  1. Emmet (一种快速编译 Html 和 CSS 的方法)
    例如:输入 div>ul.test2>li{demo$}3 按下 tab 键,将会自动生成如下代码:
 <div>
      <ul class="test">
          <li>demo1</li>
          <li>demo2</li>
          <li>demo3</li>
      </ul>
      <ul class="test">
          <li>demo1</li>
          <li>demo2</li>
          <li>demo3</li>
      </ul>
  </div>
  1. ColorPicker (颜色选择器)
    使用快捷键 Ctrl+shift+C ,弹出颜色面板,选色即可。
  2. View In Browser (在浏览器中快速打开html文件)
    安装之后,设置快捷键。

打开菜单栏Preferences中的Key Bindings-User,
打开Default (Windows).sublime-keymap文件编辑
内容如下就ok啦:

 { "keys": ["ctrl+alt+f"], "command": "open_in_browser" },

Ctrl+alt+f 就是你以后快速打开html页面的快捷键啦!!! (记得打开之前要先保存哦!)

  1. AutoFileName
    自动提示文件链接名或图片选取链接,便于快捷输入
  2. JavaScript Completions
    一种编写js代码时的提示插件
  3. Bracket Highlighter
    匹配各种配对的语法符号,如(),{},[],"",''等,适用于代码较多的时候!
  4. Sass
  5. text 3 支持sass文件
  6. jQuery
  7. text 3 支持jQuery文件
  8. Alignment
    代码对齐,比如js中写了很多变量,选中这几行,使用快捷键 Ctrl+Alt+A ,就可以全部对齐,很神奇哟!

小伙伴们赶紧去试试吧!!!

查看原文

赞 2 收藏 0 评论 0

认证与成就

  • 获得 1 次点赞
  • 获得 0 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 0 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-09-16
个人主页被 117 人浏览