摘要: loaders 定义 先了解一下webpack,webpack是一个用于针对js文件的构建工具,在被构建的js文件中,我们可以使用require语句和webpack loader,如下: css代码中的 @import与url()类似js的require()请求资源文件,css-loader 将会对 阅读全文
posted @ 2016-07-18 10:00 杨君华 阅读(3641) 评论(2) 推荐(3) 编辑
摘要: 一、建立简单的项目目录 1、创建 manager 根目录(作为项目根目录)2、执行 npm init,在根目录manager下自动生成 package.json文件3、npm install webpack --save-dev,在项目中安装 webpack npm包4、在根目录下 创建 webpa 阅读全文
posted @ 2016-06-24 18:29 杨君华 阅读(3707) 评论(1) 推荐(2) 编辑
摘要: 闲聊:新年第一天上班,看着自己15年年底写的代码,真心觉得很烂,因为年底没时间去写,一想着做后台管理需要获取一周的开始和结束日期,就慌了,项目赶着测试呢,还有好多事情未做,就直接抄袭了网上的一段错误代码,其实真的很简单,今天重新花点时间封装一下,以备后用,大神勿喷,谢谢! 一、封装为jQuery版日 阅读全文
posted @ 2016-02-14 14:19 杨君华 阅读(4526) 评论(1) 推荐(1) 编辑
摘要: 目的:select下拉框条目太多(上百),当用户选择具体项时会浪费用户很多时间去寻找,因此需要一个搜索框让用户输入关键字来匹配列表,便于用户选择示例图:1、html结构 [{"id": "1", "name": "1嘉实多级护全合成油SN级5W-30"}, {"id": "11... 阅读全文
posted @ 2015-11-09 12:54 杨君华 阅读(4031) 评论(1) 推荐(2) 编辑
摘要: 1、下载地址:http://www.sublimetext.com/3 请根据你的平台,选择适当的安装版本 安装完毕后,设定TAB键为4个空格( Preferences——>Setings-User ): 2、安装插件管理器(Package Control) 依次点击菜单栏上的view(查看)——> 阅读全文
posted @ 2015-07-17 11:01 杨君华 阅读(6257) 评论(4) 推荐(4) 编辑
摘要: 目的:记录 Zepto.js touch模块 源码阅读源码:// Zepto.js// (c) 2010-2015 Thomas Fuchs// Zepto.js may be freely distributed under the MIT license.;(functi... 阅读全文
posted @ 2015-01-28 16:51 杨君华 阅读(5569) 评论(0) 推荐(0) 编辑
摘要: 2014年下半年学习备注1、jQuery 中文APIhttp://jquery.cuishifeng.cn/2、Zepto 中文APIhttp://www.css88.com/doc/zeptojs_api/https://github.com/madrobby/zepto3、git 学习教程htt... 阅读全文
posted @ 2015-01-21 14:46 杨君华 阅读(821) 评论(2) 推荐(3) 编辑
摘要: 前言:上一篇详细的介绍了jQuery.validator( 版本v1.13.0 )的验证规则,这一篇重点讲述它的源码结构,及如何来对元素进行验证,错误消息提示的内部实现一、插件结构(组织方式)在讲述如何对元素进行验证前有必要了解它的代码组织方式,请看代码(部分省略)var plugFn = func... 阅读全文
posted @ 2014-08-29 11:51 杨君华 阅读(22193) 评论(7) 推荐(0) 编辑
摘要: 前言:jQuery.validator是一款非常不错的表单验证插件,验证方式非常简单方便,它还对HTML5做了兼容处理,了解了验证规则,就基本掌握了它的使用,下面就让我一一道来 jQuery.validator 验证规则一、在元素的class属性中添加需要验证的规则,多个规则以空格隔开邮箱:requ... 阅读全文
posted @ 2014-08-27 18:34 杨君华 阅读(14927) 评论(0) 推荐(5) 编辑
摘要: 前言:貌似以前自己也写过图片懒加载插件,但是新公司使用的是jQuery.lazyload插件,为了更好的运用,自己还是把源码看了遍,分别记录了如何使用,插件原理,各个配置属性的完整解释,demo实例,源码分析(较简短),源码分析可以配合使用,配置属性,原理进行阅读,如需转载,请注明出处博客园 华子y... 阅读全文
posted @ 2014-07-27 18:56 杨君华 阅读(18713) 评论(2) 推荐(4) 编辑
摘要: 前言:前一篇文章中重点总结了一下then方法,它主要用来处理多个异步任务按顺序执行,即前一个任务处理完了,再继续下一个,以此类推;而这一章节jQuery.when方法也是处理多个异步任务,它把多个异步任务(Promise对象)合并为一个Promise对象,这个合并后的Promise对象到底是如何来更新它的状态,即何时执行,拒绝?让我们继续往下看吧!jQuery回调、递延对象总结篇索引:jQuery回调、递延对象总结(上篇)—— jQuery.Callbacks jQuery回调、递延对象总结(中篇) —— 神奇的then方法 jQuery回调、递延对象总结(下篇) —— 解密jQuery.wh 阅读全文
posted @ 2014-01-09 15:52 杨君华 阅读(2825) 评论(1) 推荐(0) 编辑
摘要: 前言:什么叫做递延对象,生成一个递延对象只需调用jQuery.Deferred函数,deferred这个单词译为延期,推迟,即延迟的意思,那么在jQuery中又是如何表达延迟的呢,从递延对象中的then方法或许能找到这种延迟的行为,本文重点解读递延对象中的then方法jQuery回调、递延对象总结篇索引:jQuery回调、递延对象总结(上篇)—— jQuery.CallbacksjQuery回调、递延对象总结(中篇) —— 神奇的then方法jQuery回调、递延对象总结(下篇) —— 解密jQuery.when方法设计思路:在递延对象构造中,分别有三组回调对象,每一组回调对象都有与之对应的行 阅读全文
posted @ 2014-01-07 17:55 杨君华 阅读(15716) 评论(3) 推荐(0) 编辑
摘要: 前言:作为参数传递给另一个函数执行的函数我们称为回调函数,那么该回调又是否是异步的呢,何谓异步,如:作为事件处理器,或作为参数传递给(setTimeout,setInterval)这样的异步函数,或作为ajax发送请求,应用于请求各种状态的处理,我们可以称为异步回调,jQuery.Callbacks为我们封装了一个回调对象模块,我们先来看一个应用场景:// 为什么jQuery中的ready事件可以执行多个回调,这得益于我们的jQuery.Deferred递延对象(是基于jQuery.Callbacks回调模块)jQuery(function($) { console.log('docu 阅读全文
posted @ 2014-01-07 11:53 杨君华 阅读(3958) 评论(0) 推荐(0) 编辑
摘要: 一、前言当一个页面中请求的图片过多,而且图片太大,页面访问的速度是非常慢的,对用户的体验非常不友好;使用图片懒加载,可以减轻服务器的压力,增加页面的访问量,这里主要是总结一下我自己写的图片懒加载组件jQuery.imgLazyLoad;使用该组件应在img标签中设置一个imglazyload-src属性,存放图片地址。二、应用实例demo/** * component: imgLazyLoad 2013/12/12 华子yjh * invoking: jQuery.imgLazyLoad(options) * // 配置对象 options = { container... 阅读全文
posted @ 2013-12-12 13:46 杨君华 阅读(5667) 评论(2) 推荐(5) 编辑
摘要: 前言:如果你对jQuery.Callback回调对象不了解,或者只掌握其方法,但是没有通过阅读源码理解,可以先阅读前一章jQuery.Callbacks源码解读二,因为只有完全理解jQuery.Callback源码,才能真正的理解并掌握jQuery.Deferred递延对象。源码:// jQuery 1.10.2jQuery.extend({ Deferred: function( func ) { /* tuples包含三个数组 三个数组前三项分别代表jQuery回调对象中的 fire, add, jQuery.Callback... 阅读全文
posted @ 2013-10-30 15:19 杨君华 阅读(1925) 评论(6) 推荐(2) 编辑
摘要: 一、参数标记/* * once: 确保回调列表仅只fire一次 * unique: 在执行add操作中,确保回调列表中不存在重复的回调 * stopOnFalse: 当执行回调返回值为false,则终止回调队列的执行 * momery: 记录上一次fire时的参数,并在add中传递给fire和执行fire,执行时firingIndex为上一次fire时的firingLength */二、源码解读分析var optionsCache = {}, // Used for splitting on whitespace core_rnotwhite = /\S+/g;// Convert... 阅读全文
posted @ 2013-10-21 19:36 杨君华 阅读(1238) 评论(0) 推荐(2) 编辑
摘要: 一、源码思路分析总结[ 作者:华子yjh ]概要:jQuery的核心思想可以简单概括为“查询和操作dom”,今天主要是分析一下jQuery.prototype.init选择器构造函数,处理选择器函数中的参数;这个函数的参数就是jQuery()===$()执行函数中的参数,可以先看我之前写的浅析jQuery基础框架一文,了解基础框架后,再看此文。思路分析:以下是几种jQuery的使用情况(用于查询dom),每种情况都返回一个选择器实例(习惯称jQuery对象(一个nodeList对象),该对象包含查询的dom节点):1、处理 $(""), $(null), $(undefin 阅读全文
posted @ 2013-01-09 19:23 杨君华 阅读(4503) 评论(1) 推荐(2) 编辑
摘要: 一、原型模式结构1 // 定义一个jQuery构造函数2 var jQuery = function() {3 4 };5 6 // 扩展jQuery原型 7 jQuery.prototype = {8 9 };上面是一个原型模式结构,一个jQuery构造函数和jQuery实例化对象的的原型对象,我们一般是这样使用的:1 var jq = new jQuery(); //变量jq通过new关键字实例化jQuery构造函数后就可以使用原型对象中的方法,但是jQuery并不是这么使用的二、返回选择器实例 1 var jQuery = function() { 2 3 // 返回选... 阅读全文
posted @ 2012-12-27 16:47 杨君华 阅读(4437) 评论(4) 推荐(10) 编辑

深入Vue.js响应式原理

一、创建一个Vue应用

new Vue({
  data() {
    return {
      name: 'yjh',
    };
  },
  router,
  store,
  render: h => h(App),
}).$mount('#app');

 

二、实例化一个Vue应用到底发生了什么?

  1. this._init()
  2. callHook(vm, 'beforeCreate')
  3. observe(vm._data)
vm._data = vm.$options.data()

proxy(vm, _data, key) 代理到vm上访问

function proxy(vm, _data, key)() {
  Object.defineProperty(target, key, {
    get() {
      return vm._data.key
    },
    set(val) {
      vm._data.key = val
    }
  })
}
  1. callHook(vm, 'created')
  2. mountComponent(vm.$mount执行后执行mountComponent)
  3. callHook(vm, 'beforeMount')
  4. new Watcher(vm, updateComponent)
const updateComponent = () => {
  // 创建虚拟dom
  const vnode = vm._render()

  // 创建虚拟dom的过程等同于如下代码行
  // const vnode = vm.$options.render.call(vm, vm.$createElement)

  // 更新$el
  vm._update(vnode)
}
  1. callHook(vm, 'mount')

在以上发生的行为当中,第3步与第7步两者相辅相成;也是我们最需要关心的,弄清楚这两者,vue响应式原理就基本掌握了

三、如何追踪数据变化

我们都知道 数据发生变化视图也随之更新,那么首先我们得知道如何监听数据的变化

class Observer {
  constructor(value) {
    this.value = value
    this.walk(value)
  }

  walk(obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i])
    }
  }
}
function defineReactive(obj, key) {
  Object.defineProperty(obj, key, {
    get() {
      // 数据被访问
      return obj.key
    },
    set(val) {
      if (val === obj.key) {
        return
      }
      // 数据更新了
      obj.key = val
    }
  })
}

四、定义一个发布订阅的Dep类

当我们在创建虚拟dom的过程中,也就是执行vm.$createElement方法,可能会在多个地方使用到同一个数据字段(如:vm.name),即多个订阅者订阅了name的更新,因此在Vue中定义了一个发布订阅的Dep类

class Dep {
  constructor() {
    this.subs = []
  }

  addSub(sub) {
    this.subs.push(sub)
  }

  depend() {
    if (Dep.target) {
      this.addSub(Dep.target)
    }
  }

  notify() {
    this.subs.forEach(sub => sub.update())
  }

  removeSub(sub) {
    const i = this.subs.findIndex(sub)
    if (i > -1) {
      this.subs.splice(i, 1)
    }
  }
}

 

五、数据订阅者

订阅数据更新的到底是谁,我们先看看如下场景

<!-- 场景1 -->
<div>名字:{{ userInfo.name }},全名:{{ fullName }}</div>
export default {
  data() {
    return {
      userInfo: {
        name: 'junhua',
      },
    }
  },
  mounted() {
    // 场景2
    this.$watch('name', (newVal, val) => {
      // ...
    })
  },
  // 场景2
  watch: {
    name(newVal, val) {
      // ...
    }
  },
  computed() {
    // 场景3
    fullName() {
      return `yang${this.userInfo.name}`
    }
  }
}

 

从上面示例代码看,订阅数据更新的场景有:

  1. 模版插值 :new Watcher(vm, updateComponent)数据发生变化,更新组件
  2. vm.$watch : 监听单个数据做一些逻辑操作
  3. computed使用场景:计算属性

因此数据订阅者包含一个参数expOrFn([Function|String]),数据更新后需要执行的callback,如下:

class Watcher {
  constructor(vm, expOrFn, cb) {
    this.vm = vm
      if (typeof expOrFn === 'function') {
      this.getter = expOrFn
    } else {
      this.getter = parsePath(expOrFn)
    }
    this.cb = cb || () => {}
    this.value = this.get()
  }

  get() {
    Dep.target = this
    const value = this.getter.call(this.vm, this.vm)
    Dep.target = undefined
    return value
  }

  update() {
    const val = this.value
    const newVal = this.get()
    this.cb.call(this.vm, newVal, val)
  }
}

 

六、最终的观察者Observer

class Observer {
  constructor(value) {
    this.value = value
    this.walk(value)
  }

  walk(obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i],)
    }
  }
}

function defineReactive(obj, key) {
  const dep = new Dep()
  Object.defineProperty(obj, key, {
    get() {
      // 依赖收集,收集订阅者Watcher实例
      dep.depend()
      // 数据被访问
      return obj.key
    },
    set(val) {
      if (val === obj.key) {
        return
      }
      // 数据更新了
      obj.key = val
      // 通知订阅者Watcher实例更新
      dep.notify()
    }
  })
}

 

七、总结

我们再来回顾下实例化Vue应用的最重要的两点

observe(vm._data)
// vm.$mount()
const componentUpdateWatcher = new Watcher(vm, updateComponent)

updateComponent在更新渲染组件时,会访问1或多个数据模版插值,当访问数据时,将通过getter拦截器把componentUpdateWatcher作为订阅者添加到多个依赖中,每当其中一个数据有更新,将执行setter函数,对应的依赖将会通知订阅者componentUpdateWatcher执行update,即执行updateComponent;至此Vue数据响应式目的已达到,再来看官网的这张图片就很好理解了

 

 

 

github地址   文章来源:博客园-杨君华,转载请注明出处:杨君华

 

posted @ 2019-08-18 23:01 杨君华 阅读(617) 评论(0) 推荐(0) 编辑
摘要: Native/Webview bridge for Hybrid 安装 npm i --save webview-bridge 特点 支持自定义app URL scheme 支持多种处理方式(全部涵盖) 支持Promise处理回调 使用 import Bridge from 'hybride-web 阅读全文
posted @ 2017-11-15 22:02 杨君华 阅读(812) 评论(0) 推荐(0) 编辑
摘要: 序言:应朋友要求随手写了一下移动端 css实现自适应正圆 ( 宽高随着手机屏幕宽度自适应 ) ,以备后用 LESS代码: .adaptive-circle { margin: 50px auto 0; width: 80%; height: 0; padding-top: 80%; border-r 阅读全文
posted @ 2016-02-25 11:40 杨君华 阅读(5600) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示