answershuto 最近的时间轴更新
answershuto

answershuto

🏢  前端开发
V2EX 第 221230 号会员,加入于 2017-03-15 21:51:52 +08:00
聊聊 keep-alive 组件的使用及其实现原理
前端开发  •  answershuto  •  2017-11-13 10:14:52 AM  •  最后回复来自 pabupa
1
Vuex 源码解析
前端开发  •  answershuto  •  2017-11-01 15:54:24 PM  •  最后回复来自 geek123
7
从 template 到 DOM(Vue.js 源码角度看内部运行机制)
前端开发  •  answershuto  •  2017-10-15 21:21:00 PM  •  最后回复来自 SourceMan
1
聊聊 Vue.js 的 template 编译
前端开发  •  answershuto  •  2017-10-08 21:50:10 PM
Vue.js 源码——事件机制
前端开发  •  answershuto  •  2017-09-28 00:30:16 AM  •  最后回复来自 Lisp
3
从 Vue.js 源码看异步更新 DOM 策略及 nextTick
  •  1   
    Vue.js  •  answershuto  •  2017-09-24 23:40:39 PM  •  最后回复来自 SilentDepth
    1
    VirtualDOM 与 diff(Vue 实现)
    前端开发  •  answershuto  •  2017-09-18 20:57:12 PM  •  最后回复来自 answershuto
    1
    说说 VNode 节点(Vue.js 实现)
    JavaScript  •  answershuto  •  2017-09-11 10:49:50 AM  •  最后回复来自 66beta
    7
    从 Vue.js 源码角度再看数据绑定
  •  2   
    前端开发  •  answershuto  •  2017-09-05 10:00:33 AM  •  最后回复来自 codermagefox
    1
    一款可视化编辑手机 H5 页面的单页应用 WebApp
    分享创造  •  answershuto  •  2017-08-30 18:11:45 PM  •  最后回复来自 answershuto
    7
    answershuto 最近回复了
    2017-10-30 11:17:59 +08:00
    回复了 answershuto 创建的主题 前端开发 Vuex 源码解析
    @smallpath 不错~其实主要就是抽离核心的 Store 操作,以及最关键用 Vue 对象来实现数据的“响应式化”。
    2017-10-30 11:02:53 +08:00
    回复了 answershuto 创建的主题 前端开发 Vuex 源码解析
    @SourceMan 👌,我下次注意~
    2017-10-30 08:17:26 +08:00
    回复了 answershuto 创建的主题 前端开发 Vuex 源码解析
    ### unregisterModule

    ```javascript
    /* 注销一个动态 module */
    unregisterModule (path) {
    /* 转化称 Array */
    if (typeof path === 'string') path = [path]

    if (process.env.NODE_ENV !== 'production') {
    assert(Array.isArray(path), `module path must be a string or an Array.`)
    }

    /*注销*/
    this._modules.unregister(path)
    this._withCommit(() => {
    /* 获取父级的 state */
    const parentState = getNestedState(this.state, path.slice(0, -1))
    /* 从父级中删除 */
    Vue.delete(parentState, path[path.length - 1])
    })
    /* 重制 store */
    resetStore(this)
    }
    ```

    同样,与 registerModule 对应的方法 unregisterModule,动态注销模块。实现方法是先从 state 中删除模块,然后用 resetStore 来重制 store。

    ### resetStore

    ```javascript
    /* 重制 store */
    function resetStore (store, hot) {
    store._actions = Object.create(null)
    store._mutations = Object.create(null)
    store._wrappedGetters = Object.create(null)
    store._modulesNamespaceMap = Object.create(null)
    const state = store.state
    // init all modules
    installModule(store, state, [], store._modules.root, true)
    // reset vm
    resetStoreVM(store, state, hot)
    }
    ```

    这里的 resetStore 其实也就是将 store 中的_actions 等进行初始化以后,重新执行 installModule 与 resetStoreVM 来初始化 module 以及用 Vue 特性使其“响应式化”,这跟构造函数中的是一致的。


    ## 插件

    Vue 提供了一个非常好用的插件[Vue.js devtools]( https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)

    ```javascript
    /* 从 window 对象的__VUE_DEVTOOLS_GLOBAL_HOOK__中获取 devtool 插件 */
    const devtoolHook =
    typeof window !== 'undefined' &&
    window.__VUE_DEVTOOLS_GLOBAL_HOOK__

    export default function devtoolPlugin (store) {
    if (!devtoolHook) return

    /* devtoll 插件实例存储在 store 的_devtoolHook 上 */
    store._devtoolHook = devtoolHook

    /* 出发 vuex 的初始化事件,并将 store 的引用地址传给 deltool 插件,使插件获取 store 的实例 */
    devtoolHook.emit('vuex:init', store)

    /* 监听 travel-to-state 事件 */
    devtoolHook.on('vuex:travel-to-state', targetState => {
    /* 重制 state */
    store.replaceState(targetState)
    })

    /* 订阅 store 的变化 */
    store.subscribe((mutation, state) => {
    devtoolHook.emit('vuex:mutation', mutation, state)
    })
    }
    ```

    如果已经安装了该插件,则会在 windows 对象上暴露一个__VUE_DEVTOOLS_GLOBAL_HOOK__。devtoolHook 用在初始化的时候会触发“ vuex:init ”事件通知插件,然后通过 on 方法监听“ vuex:travel-to-state ”事件来重置 state。最后通过 Store 的 subscribe 方法来添加一个订阅者,在触发 commit 方法修改 mutation 数据以后,该订阅者会被通知,从而触发“ vuex:mutation ”事件。

    ## 最后

    Vuex 是一个非常优秀的库,代码量不多且结构清晰,非常适合研究学习其内部实现。最近的一系列源码阅读也使我自己受益匪浅,写这篇文章也希望可以帮助到更多想要学习探索 Vuex 内部实现原理的同学。
    2017-09-18 20:57:12 +08:00
    回复了 answershuto 创建的主题 前端开发 VirtualDOM 与 diff(Vue 实现)
    由于平台字数限制放不下了,接上文。

    ## DOM 操作

    由于 Vue 使用了虚拟 DOM,所以虚拟 DOM 可以在任何支持 JavaScript 语言的平台上操作,譬如说目前 Vue 支持的浏览器平台或是 weex,在虚拟 DOM 的实现上是一致的。那么最后虚拟 DOM 如何映射到真实的 DOM 节点上呢?

    Vue 为平台做了一层适配层,浏览器平台见[/platforms/web/runtime/node-ops.js]( https://github.com/answershuto/learnVue/blob/master/vue-src/platforms/web/runtime/node-ops.js)以及 weex 平台见[/platforms/weex/runtime/node-ops.js]( https://github.com/answershuto/learnVue/blob/master/vue-src/platforms/weex/runtime/node-ops.js)。不同平台之间通过适配层对外提供相同的接口,虚拟 DOM 进行操作真实 DOM 节点的时候,只需要调用这些适配层的接口即可,而内部实现则不需要关心,它会根据平台的改变而改变。

    现在又出现了一个问题,我们只是将虚拟 DOM 映射成了真实的 DOM。那如何给这些 DOM 加入 attr、class、style 等 DOM 属性呢?

    这要依赖于虚拟 DOM 的生命钩子。虚拟 DOM 提供了如下的钩子函数,分别在不同的时期会进行调用。

    ```JavaScript
    const hooks = ['create', 'activate', 'update', 'remove', 'destroy']

    /*构建 cbs 回调函数,web 平台上见 /platforms/web/runtime/modules*/
    for (i = 0; i < hooks.length; ++i) {
    cbs[hooks[i]] = []
    for (j = 0; j < modules.length; ++j) {
    if (isDef(modules[j][hooks[i]])) {
    cbs[hooks[i]].push(modules[j][hooks[i]])
    }
    }
    }
    ```

    同理,也会根据不同平台有自己不同的实现,我们这里以 Web 平台为例。Web 平台的钩子函数见[/platforms/web/runtime/modules]( https://github.com/answershuto/learnVue/tree/master/vue-src/platforms/web/runtime/modules)。里面有对 attr、class、props、events、style 以及 transition (过渡状态)的 DOM 属性进行操作。

    以 attr 为例,代码很简单。

    ```JavaScript
    /* @flow */

    import { isIE9 } from 'core/util/env'

    import {
    extend,
    isDef,
    isUndef
    } from 'shared/util'

    import {
    isXlink,
    xlinkNS,
    getXlinkProp,
    isBooleanAttr,
    isEnumeratedAttr,
    isFalsyAttrValue
    } from 'web/util/index'

    /*更新 attr*/
    function updateAttrs (oldVnode: VNodeWithData, vnode: VNodeWithData) {
    /*如果旧的以及新的 VNode 节点均没有 attr 属性,则直接返回*/
    if (isUndef(oldVnode.data.attrs) && isUndef(vnode.data.attrs)) {
    return
    }
    let key, cur, old
    /*VNode 节点对应的 Dom 实例*/
    const elm = vnode.elm
    /*旧 VNode 节点的 attr*/
    const oldAttrs = oldVnode.data.attrs || {}
    /*新 VNode 节点的 attr*/
    let attrs: any = vnode.data.attrs || {}
    // clone observed objects, as the user probably wants to mutate it
    /*如果新的 VNode 的 attr 已经有__ob__(代表已经被 Observe 处理过了), 进行深拷贝*/
    if (isDef(attrs.__ob__)) {
    attrs = vnode.data.attrs = extend({}, attrs)
    }

    /*遍历 attr,不一致则替换*/
    for (key in attrs) {
    cur = attrs[key]
    old = oldAttrs[key]
    if (old !== cur) {
    setAttr(elm, key, cur)
    }
    }
    // #4391: in IE9, setting type can reset value for input[type=radio]
    /* istanbul ignore if */
    if (isIE9 && attrs.value !== oldAttrs.value) {
    setAttr(elm, 'value', attrs.value)
    }
    for (key in oldAttrs) {
    if (isUndef(attrs[key])) {
    if (isXlink(key)) {
    elm.removeAttributeNS(xlinkNS, getXlinkProp(key))
    } else if (!isEnumeratedAttr(key)) {
    elm.removeAttribute(key)
    }
    }
    }
    }

    /*设置 attr*/
    function setAttr (el: Element, key: string, value: any) {
    if (isBooleanAttr(key)) {
    // set attribute for blank value
    // e.g. <option disabled>Select one</option>
    if (isFalsyAttrValue(value)) {
    el.removeAttribute(key)
    } else {
    el.setAttribute(key, key)
    }
    } else if (isEnumeratedAttr(key)) {
    el.setAttribute(key, isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true')
    } else if (isXlink(key)) {
    if (isFalsyAttrValue(value)) {
    el.removeAttributeNS(xlinkNS, getXlinkProp(key))
    } else {
    el.setAttributeNS(xlinkNS, key, value)
    }
    } else {
    if (isFalsyAttrValue(value)) {
    el.removeAttribute(key)
    } else {
    el.setAttribute(key, value)
    }
    }
    }

    export default {
    create: updateAttrs,
    update: updateAttrs
    }

    ```

    attr 只需要在 create 以及 update 钩子被调用时更新 DOM 的 attr 属性即可。
    2017-09-11 10:25:49 +08:00
    回复了 answershuto 创建的主题 JavaScript 说说 VNode 节点(Vue.js 实现)
    @dcoder 😊3q
    2017-09-11 10:25:30 +08:00
    回复了 answershuto 创建的主题 JavaScript 说说 VNode 节点(Vue.js 实现)
    @sansansan333 时间花下去了,总会有收获的哈~
    2017-09-11 10:25:03 +08:00
    回复了 answershuto 创建的主题 JavaScript 说说 VNode 节点(Vue.js 实现)
    @codermagefox 哈哈谢谢
    2017-08-30 18:11:45 +08:00
    回复了 answershuto 创建的主题 分享创造 一款可视化编辑手机 H5 页面的单页应用 WebApp
    @biuuu 😂 不带解释以为是骂人的。。。
    2017-08-30 12:23:37 +08:00
    回复了 answershuto 创建的主题 分享创造 一款可视化编辑手机 H5 页面的单页应用 WebApp
    @lqzhgood 作为技术可能多多少少对这些名称不是很喜欢,但是我似乎找不到别的更合适且让人熟悉的名词去描述 H5 这个东西了。
    2017-08-30 09:03:31 +08:00
    回复了 answershuto 创建的主题 分享创造 一款可视化编辑手机 H5 页面的单页应用 WebApp
    @v1024 H5 按照我的理解是现在常用于微信里做营销用的类似 ppt 的 HTML5 页面的称呼,所以我没用 HTML5 而用了 H5,因为这个项目就是为了产出 H5 的页面的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2675 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 12:14 · PVG 20:14 · LAX 04:14 · JFK 07:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.