weex官方weex-hackernews源码解读

一、weex-hackernews介绍

Weex官方基于Weex和Vue开发了一个的完整项目,在项目中使用了Vuex和vue-router,能够实现同一份代码,在 iOS、Android、Web 下都能完整地工作。weex-hackernews的项目地址。

1、下载

下载地址:https://github.com/weexteam/weex-hackernews
直接下载zip包下来

2、运行weex-hackernews

2.1 准备:

     1.搭建Weex本地开发环境,可以前往Weex官方按照开发文档教程进行搭建搭建地址:http://weex.apache.org/cn/guide/set-up-env.html。
     2.下载开发工具:WebStorm、AndroidStudio、Android SDK、CocoaPods

2.2 安装

安装依赖:

npm install

编译代码:

# 生成 Web 平台和 native 平台可用的 bundle 文件
# 位置:
# dist/index.web.js
# dist/index.web.js
npm run build

# 监听模式的 npm run build
npm run dev

拷贝bundle文件:

# 将生成的 bundle 文件拷贝到 Android 项目的资源目录
npm run copy:android

# 将生成的 bundle 文件拷贝到 iOS 项目的资源目录
npm run copy:ios

# run both copy:andriod and copy:ios
npm run copy

# 注意:window系统下,修改下package.json文件,copy:android对应的命令行,官网下载下来的是mac系统命令行,要进行修改
修改前
"copy:android": "cp dist/index.weex.js android/app/src/main/assets/index.js"
修改后:
"copy:android":"xcopy.\\dist\\index.weex.js.\\android\\app\\src\\main\\assets\\index.js"

启动Web服务

npm run serve

启动服务后监听1337端口,访问 http://127.0.0.1:1337/index.html 即可在浏览器中预览页面

启动Android项目

     启动Android项目,首先安装Android Studio和Android SDK,并配置好基本的开发环境;用Android Studio 打开 android 目录的项目,等待自动安装完依赖以后,即可启动模拟器或者真机预览页面;

启动 iOS 项目

     启动 iOS 项目,首先应该配置好 iOS 开发环境 并且安装 CocoaPods 工具;进入 ios 目录,使用 CocoaPods 安装依赖;

pod install

使用 Xcode 打开ios目录中的项目(HackerNews.xcworkspace),然后即可启动模拟器预览页面。

注:如果想要在真机上查看效果,还需要配置开发者签名等信息。

2.3 运行效果图

  • 首页

    weex官方weex-hackernews源码解读_第1张图片

  • 具体详情页

    weex官方weex-hackernews源码解读_第2张图片

二、代码分析

1  功能目录

将项目导入WebStorm里,功能目录分析

|-- android                          // android工程
|-- dist                             // android工程
|   |--dist/index.web.js             //Web平台bundle文件
|   |--dist/index.weex.js            //native平台bundle文件
|-- ios                              // ios工程
|-- src                              //项目的vue文件
|   |--components                    //vue组件(封装组件)
|   |--filters                       //vue的过滤器
|   |--mixins                        //vue的mixins(混合)
|   |--store                         //vuex(vue的状态管理器)
|   |--views                         //视图
|   |--App.vue                       //主UI界面
|   |--entry.js                      //入口文件
|   |--router.js                     //vue的路由声明

|-- .babelrc                         // ES6语法编译配置
|-- package.json                     // 配置项目相关信息,通过执行 npm init 命令创建
|-- qrcode.jpg                       //二维码
|-- README.md                        // 项目说明
|-- webpack.config.js                // 程序打包配置

2  vue路由router

2.1  vue-router 介绍

vue-router是vue.js官方支持的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。

2.2  vue-router知识点

这里vue-router的知识点,这边就不进行阐述,因为官方上有详细的介绍:https://router.vuejs.org/zh-cn/,如果快速入手推荐看之前看过的文章:http://blog.csdn.net/sinat_17775997/article/details/52549123。

2.2  项目路由分析

router.js文件

import Router from 'vue-router'
import StoriesView from './views/StoriesView.vue'
import ArticleView from './views/ArticleView.vue'
import CommentView from './views/CommentView.vue'
import UserView from './views/UserView.vue'

Vue.use(Router)

// Story view factory
function createStoriesView (type) {
  return {
    name: `${type}-stories-view`,
    render (createElement) {
      return createElement(StoriesView, { props: { type }})
    }
  }
}

export default new Router({
  // mode: 'abstract',
  routes: [
    { path: '/top', component: createStoriesView('top') },
    { path: '/new', component: createStoriesView('new') },
    { path: '/show', component: createStoriesView('show') },
    { path: '/ask', component: createStoriesView('ask') },
    { path: '/job', component: createStoriesView('job') },
    { path: '/article/:url(.*)?', component: ArticleView },
    { path: '/item/:id(\\d+)', component: CommentView },
    { path: '/user/:id', component: UserView },
    { path: '/', redirect: '/top' }
  ]
})
  • 首先导入Router
import Router from 'vue-router'
  • Vue注入router
Vue.use(Router)
  • router的路由配置,导入各种View
export default new Router({
  // mode: 'abstract',
  routes: [
    { path: '/top', component: createStoriesView('top') },
    { path: '/new', component: createStoriesView('new') },
    { path: '/show', component: createStoriesView('show') },
    { path: '/ask', component: createStoriesView('ask') },
    { path: '/job', component: createStoriesView('job') },
    { path: '/article/:url(.*)?', component: ArticleView },
    { path: '/item/:id(\\d+)', component: CommentView },
    { path: '/user/:id', component: UserView },
    { path: '/', redirect: '/top' }
  ]
})
  • router的入口路径是path’/’,这在后面分析App.vue会讲到。然而路由的路劲’/’重定向到’/top’,所以’/top’对应的文件才是真正App入口UI界面。
{ path: '/', redirect: '/top' }
  • 接着看对应着路径对应的’/top’对应的component.
{ path: '/top', component: createStoriesView('top') }

如果看完上面给的两个介绍router的链接,就知道path代表匹配路径,component对应组件的文件。可能大家都会问‘/top’对应明明是createStoriesView(‘top’),我们沿着createStoriesView(type)方法看下去:

function createStoriesView (type) {
  return {
    name: `${type}-stories-view`,
    render (createElement) {
      return createElement(StoriesView, { props: { type }})
    }
  }
}

其实会发现在‘/top’对应的文件是StoriesView,其中props对应是传入该组件的参数。

  • 路由跳转
    路由跳转有两种形式:声明和编程。
#声明:
"...">
#编程
router.push(...)
router.push({ path: 'home' }) 
router.push('home')
router.push({ name: 'user', params: { userId: 123 }})
//params跳转到组件传入参数key为userId,value为123
//跳转到的界面接收:this.$router.param.userId;

工程的路由的跳转封装在mixins/index.js文件中:

export default {
  methods: {
    jump (to) {
      if (this.$router) {
        this.$router.push(to)
      }
    }
  }
}

大家肯定疑问,mixins/index.js什么时候被注入到vue,能全局调用?其实在入口文件entry.js

// register global mixins.
Vue.mixin(mixins)

3  vue状态管理库Vuex

3.1  Vuex 介绍

Vuex是专为Vue.js应用程序开发的状态管理模型。它采用集中式存储应用的所有组件的状态(理想),并以相应规则保证状态已一种可预测的方式变化。Vuex也是集成到Vuex的官方调试工具

什么是”状态管理模式”?

包含以下几部分:

  • state,驱动应用的数据源
  • view,以声明方式将state映射到视图;
  • action,响应在view上的用户输入导致的状态变化

以下是一个表示“单向数据流”理念的示意

    Vuex的基本思想,借鉴Flu、Redux和The Elm Architechture,vuex是专门为Vue.js设计的状态管理库,利用响应体制来进行高效的状态更新。

Store
    每个Vuex的应用都有一个核心的store(仓库)。”store”是一个容器,里面存储应用的大部分的状态(state)。相当于一个全局对象,但是有跟全局对象有所区别的是,vuex的状态存储是响应式,只要store状态发生变化,那么相应的引用到的组件会跟着更新。
    store的核心内容由State、Getters、Mutations、Actions、Modules组成。

  • state:全局唯一数据源,定义着weex-hackernews工程的列表lists、用户users、items详情等数据;
  • getters:其实主要就是state数据处理,进行过滤操作;
  • mutation:唯一可以更改state里面的数据;
    -Actions:类似mutation,不同在于action提交的是mutation,而不是直接变更数据状态,Actions可以包含任意异步操作。

  • Modules:使用单一状态树,导致应用的所有状态集中到一个很大的对象。但是,当应用变得很大时,store 对象会变得臃肿不堪,Vuex 允许将 store 分割到模块(module),每个模块拥有自己的 state、mutation、action、getters.

        我们直接看下图官方的流程图,state作为全局数据源,我们通过dispatch触发action动作,action做业务处理在提交Mutation来改变State,State改变后自动Render到Vue的component组件上,从而实现单向数据流。
        看上面的理论大体懂个流程,有可能存在一知半解,后面直接通过项目的代码进行整个流程进行分析,到时基本可以明白Vuex的流程了。

4  入口文件

App.vue 文件

// import Vue from 'vue'
import App from './App.vue'                 //加载UI主界面
import router from './router'               //加载vue路由 
import store from './store'                 //加载vuex的store
import { sync } from 'vuex-router-sync'
import * as filters from './filters'        //加载vue的fitlter(过滤器)
import mixins from './mixins'                //加载vue的mixins(混合)

sync(store, router)

Object.keys(filters).forEach(key => {
  Vue.filter(key, filters[key])
})

Vue.mixin(mixins)

//vue扩展路由、状态管理器、入口UI主界面
new Vue(Vue.util.extend({ el: '#root', router, store }, App))             

router.push('/')     //默认路由跳转路径

该文件主要任务是路由(router)、状态管理器(store)、view的导入,
这边的路由的入口路径’/’

router.push('/')  

在router中的路由声明我们有提到过的路由的路口路径,就是在这边实现。

5  主界面

5.1  StoriesView主界面

StoriesView.vue
其实就是首页界面。
我们可以看到*.vue文件有三部分组成: