标签 Vue 下的文章

Vue 双向绑定原理

以前写 AngularJS 的时候曾经分析过其双向绑定脏检查机制, 转向 Vue 开发也挺久了但一直没有去研究其源码, 也就前段时间去研究下了其 nextTick 的实现. 今天主要看了 Vue 双向绑定的机制, 感觉 Vue 的代码比起 AngularJS 要容易看很多了, 不过东西也挺多的, 代码质量不错, 写篇文章巩固下.

源码分析

Vue 实现双向绑定有一个非常重要的方法就是 defineReactive, 搞懂这个方法对理解 Vue 的双向绑定帮助非常大. 文章源码篇幅比较多, 但其实代码并不难理解.

defineReactive 大致过程如下:

(注: 结合我看的最新的源码, 图中观察整体 data 应该是用的 observe 方法而不是 defineProperty, 这两个方法区别在于是否需要劫持当前对象自身的 getter, setter.)

defineReactive

源码如下:

- 阅读剩余部分 -

聊聊 Webpack 使用

老早的时候就听说了 Webpack 这个工具, 当时大概的印象就是类似 Gulp 这样的东西, 并且看起来好像挺复杂的. 直到学习 React 的时候才开始接触 Webpack, 才知道 Webpack 更多的是做模块化的工作. 不过当时也是乱配置一通能用就行=.=.

现在 Vue 标配也是用 Webpack 了. Webpack 其实并没有想象中的那么复杂, 其实最核心的还是 loader 那一块. 这次就主要聊一聊 Webpack. 我用的是 Webpack 最新版本 2.1.0-beta.27.

what-is-webpack.png

Loader

Loader 是 Webpack 的核心, 它会自动查找项目中的我们指定的文件类型, 然后使用我们指定的 Loader 进行处理. 例如:

module: {
  rules: [{
    test:    /\.vue$/,
    loader:  'vue-loader',
    options: {
      loaders: {
        css: ExtractTextPlugin.extract({
          loader:         ['css-loader?minimize', 'postcss-loader'],
          fallbackLoader: 'vue-style-loader'
        })
      }
    }
  }, {
    test:    /\.js$/,
    loader:  'babel-loader',
    exclude: /node_modules/
  }, {
    test:   /\.css$/,
    loader: ExtractTextPlugin.extract({
      loader: ['css-loader?minimize', 'postcss-loader']
    })
  }, {
    test:   /\.(eot|woff|woff2|ttf)([\?]?.*)$/,
    loader: 'file-loader'
  }, {
    test:   /\.(png|jpg|gif|svg|ico)$/,
    loader: 'url-loader?limit=8192',
  }]
},

对于 Vue 文件, 我们要让 vue-loader 来处理, 这里可以先忽略 ExtractTextPlugin 部分, 它作用是提取 CSS 这个在后面会提. 对于 .js 文件, 我们使用 babel-loader 来处理, 我们可以在项目配置一个 .babelrc 文件来指定我们使用的 presets 和 plugins.

- 阅读剩余部分 -

拥抱 vue 和 vuex

最近一段时间写了两个玩意, 一个是基于 PEG.js 的 XML Parser, 前面有一条博客说了 PEG.js 这东西, 事后自己也模仿着写出了这个 XML 解析器, 感觉并不难, 写着玩玩而已.

另外, 最近花时间特别多的另一件事就是写了一个 RSS 订阅器. 一开始写这个订阅器, 心想上一个项目代码不忍直视, 感觉自己需要写一些能拿出手的代码, 加上学校课程刚好要求做一些东西, 以及自己最近迷上了使用 RSS 订阅器这个东西(这么多理由=.=), 于是就自己动工开搞.

目前订阅器已经基本完工了, RSS 订阅器的网址是 www.enjoyrss.com, 项目开源在 Github 上面, 对于对 RSS 有兴趣或者想学习 Vue2, Vuex 或 Angular1 的人可能会有一些帮助. 额对了, 还有就是后端用的是 Koa2, 前后端鉴权专门在上一篇博客提了下, 想了解 Koa2 的人也可以看下.

数据流动问题

其实每次做一个新的东西的时候, 我都会尽量尝试去使用各种新的技术和用法. 这样才能学到更多的东西. 在这个 RSS 订阅器中, 一开始我只是把自己认为的各种 Angular 最佳实践在项目中都运用了下, 想写出能够体现自己 Angular 水平的代码, 为此前面还写了一篇博客说一些我认为的哪些算是最佳实践. 但其实, 对 Angular 使用已经相当熟悉的我, 并没有在这一次中收获什么新的知识. 要说有, 大概就是前面那博客提到的一些 Angular 最新版本的一些新特性例如 Component 之类的吧, 然而自己并没有花时间去看.

在这个项目中, 另外的一点感受就是 Angular 的跨组件通信难题. 确切的说我觉得这个项目并不适合使用 Angular 来写. 例如

website.png

左边有一个订阅源栏, 它的未读数量要相应右侧的点击文章, 标记全部已读等事件. 它的订阅源列表也要对右侧的订阅和取消订阅事件做出相应. 为了缩减频繁的跨组件通信, 我将下方状态栏直接拆分成三条, 由各自的组件提供其状态栏覆盖原默认只有背景色的状态栏. 但跨组件通信仍然存在, 单单左侧面板就存在着五个事件监听.

$scope.$on('EXPAND', () => vm.expand = !vm.expand)
$scope.$on('FOLD', () => vm.expand = false)
$scope.$on('ADD_FEED', (event, data) => {
  if (vm.feeds.default) {
    vm.feeds.default.push(data)
  } else {
    vm.feeds['default'] = [data]
  }
})
$scope.$on('DELETE_FEED', (event, data) => {
  vm.feeds = _.mapObject(vm.feeds, feeds => feeds = _.filter(feeds, feed => feed.feed_id !== data.feed_id))
})
$scope.$on('READ_POST', (event, data) => {
  vm.feeds = _.mapObject(vm.feeds, feeds => _.each(feeds, feed => feed.feed_id === data ? feed.unread-- : ''))
})

我需要监听折叠事件, 这个动作在其他组件被触发. 需要监听添加订阅源和取消订阅源事件, 并修改订阅源列表. 需要监听已读事件, 并对相应订阅源的未读文章数做减1操作...

在有些应用场景, 存在着需要大量父子组件通信, 兄弟组件通信, 以及没有父子和兄弟关系的组件之间的通信的行为, 这种时候, Angular 虽然也能解决, 但是不得不说 Angular 这种频繁的跨组件通信很容易产生问题, 特别是当一个组件可以被多个组件修改的时候.

- 阅读剩余部分 -