聊聊VueJs 组件化编程

各位同学,大家晚上好,我是Awe,大学退学,目前在北京从事前端的工作,因为之前入门前端就开始使用Vuejs,算有一些爬坑经历。受豪情大大委托,花大家一点时间和大家聊聊我使用Vuejs的经历,主要内容就是讲讲Vuejs组件化相关的一些点;因为我能力有限,可能会有理解不到位的地方,希望群里大神指正,一起交流。

前端开发的现状

随着互联网设备的带宽和硬件的发展,web的应用的交互越来越重。

想开发的复杂交互的网站怎么办?
没关系,一大波前端框架来拯救你。

这个是我找到的一张图,是一些最近几年出现的前端框架。左上角的有Angular、Ember、BackBone、Knockout,还有今天即将安利的Vue;这里其他位置我认识的还有Meteor,感觉它是非常未来的框架,实时的特性非常excited,还有右上的Polymer、React。

怎么选择前端框架

我只是想安静地写前端

作为一个选择恐惧症,面临这么多选择的时候是很苦恼的

其实作为一个安静的前端,只是需要一个不需要太多时间成本来学习,快速的上手开发业务,并使得项目的开发和用户体验有可见的提升(用户给好评,老板很满意,升值加薪,走上人生巅峰!)。

那么我们就进入正题安利 Vue.js

Vue.js

Reactive Components for Modern Web Interfaces
数据驱动的组件,为现代化的 Web 界面而生
最新版本是 2.0 23k star

尤小右 Evan You
@youyuxi
多说 / Google / Meteor
发布于 2014 年 2 月

Vue.js 主要是干啥的?

它是一个 MVVM 前端框架
Model / View / ViewModel
我们不需要撰写任何 DOM 操作代码:被绑定增强的 HTML 模板是底层数据状态的声明式的映射,数据不过是普通 JavaScript 对象。我们的视图完全由数据驱动。

数据驱动?

演示这个例子: http://codepen.io/awee/pen/grjGbB

Vue.js 怎么实现的?


vue将普通的对象的属性通过Object.defineProperty转换为ES5特性之一的 getter/setter,模板中每个指令/数据绑定都有一个对应的 watcher 对象, 当修改对象值的时,首先会触发属性的setter,在setter被调用时,会触发 watcher 重新计算 ,也就会导致它的关联指令更新 DOM。

Vue.js 的核心是一个响应的数据绑定系统,它让数据与 DOM 保持同步非常简单。在使用 jQuery 手工操作 DOM 时,我们的代码常常是命令式的、重复的与易错的。Vue.js 拥抱数据驱动的视图概念。通俗地讲,它意味着我们在普通 HTML 模板中使用特殊的语法将 DOM “绑定”到底层数据。一旦创建了绑定,DOM 将与数据保持同步。每当修改了数据,DOM 便相应地更新。这样我们应用中的逻辑就几乎都是直接修改数据了,不必与 DOM 更新搅在一起。这让我们的代码更容易撰写、理解与维护。

为什么要用Vue.js

  • 清晰简单的API让业务代码更好的组织
  • 解决了前端交互复杂而带来的性能问题
  • 健全、颜值高的官⽅⽂档
  • 完整的开发生态链

那些公司在用Vue.js

Google,Facebook,Airbnb,
微博 小米 阿里巴巴,百度,饿了么,58

前端组件化?


前端组件化得核心思路就是将一个巨大复制的东西拆分成粒度合理的小东西。

使用Vue单文件组件


在典型的 Vue.js 项目中,我们会把界面拆分为多个小组件,每个组件在同一地方封装它的 CSS 样式,模板和 JavaScript 定义。
使用vue官方的vue-loader + webpack还可以给其中的style template 和 script使用各种预、后处理器来编译,比如style可以使用sass、less、postcss等,在掘金 template是写的jade,非常怀念写jade(pug)的日子。至于 script 当然推荐是来写 ES6(+7)。
这里不少功能涉及到webpack相关配置,不过vue有官方脚手架工具vue-cli,它也有几个模板和模板内的配置选项,可快速搭适合建你的应用开发环境。

使用 Props 传递数据

<!-- parent.vue -->
<template>
    <div>
        <!-- 默认为单向绑定 -->
        <child :msg="parentMsg"></child>
    </div>
</template>
<script>
import child from './child'
export default {
    data () {
        return {
            parentMsg: 'some words'
        }
    },
    components: {
        child
    }
}
</script>

<!-- child.vue -->
<template>
    <div>
        {{msg}}
    </div>
</template>

<script>
    export default {
        props: {
           msg: String
        }
    }
</script>

组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用 props 把数据传给子组件。
“prop” 是组件数据的一个字段,期望从父组件传下来。子组件需要显式地用 props 选项,props的声明可以是简单的数组方式,也可以是对象方式,可以包含类型验证和默认值。

props: ['msg', 'otherMsg']

props: {
    msg: String,
    otherMsg: {
        type: String,
        default () {
            return 'it's default str'
        }
    }
}

使用 $emit 传递事件

<!-- parent.vue -->
<template>
    <div>
        <child @child-ready="handler"></child>
    </div>
</template>
<script>
import child from './child'
export default {
    components: {
        child
    },
    methods: {
        handler (msg) {
            console.log(msg)
        } 
    }
}
</script>

<!-- child.vue -->
<template>
    <div>
        it's child.vue
    </div>
</template>

<script>
    export default {
        ready () {
            this.sayReady()
        },
        methods: {
            sayReady () {
                this.$emit('child-ready', 'Hello!')
            }
        }
    }
</script>

我们先来看看这两段代码,这个两个是一个简单的父子组件的事件通信例子...

Vue 在它的组件系统中实现了一个用于组件树中通信的自定义事件的接口,任何一Vue实例都是一个事件节点,我们可以使用$emit在它上面触发事件,和DOM事件类似,Vue的事件是冒泡向上传递,不过不同的是,会在第一次触发回调之后就停止冒泡,当然你也可以在回调中 return true 就会继续向上传递。

使用 Slot 分发内容

<!-- parent.vue -->
<template>
    <div>
        <child>
          <p>This is some original content</p>
        </child>
    </div>
</template>
<script>
import child from './child'
export default {
    components: {
        child
    }
}
</script>
<!-- child.vue -->
<template>
    <div>
      <h1>This is my component!</h1>
      <slot>
        如果没有分发内容则显示我。
      </slot>
    </div>
</template>
<!-- 渲染结果 -->
<div>
    <div>
      <h1>This is my component!</h1>
      <p>This is some original content</p>
    </div>
</div>

slot 是Vue.js 的内容分发 API,参照了当前 Web 组件规范草稿,使用特殊的 <slot> 元素作为原始内容的插槽

编译作用域

<child>
  <p>{{ msg }}<p>
</child>

这里的 msg 就是在父组件的作用域内的数据
父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译

具名 Slot
子组件:

<div>
  <slot name="one"></slot>
  <slot></slot>
  <slot name="two"></slot>
</div>

父组件模板:

<multi-insertion>
  <p slot="one">One</p>
  <p slot="two">Two</p>
  <p>Default A</p>
</multi-insertion>

渲染结果

<div>
  <p slot="one">One</p>
  <p>Default A</p>
  <p slot="two">Two</p>
</div>

单个 Slot应该很好理解,那我们来看看vue是如何处理多个slot插入的。我们可以看到在子组件的 slot 中多了 一个name的属性,与它相对应的就是 父子间中DOM 的 slot属性,Vue 通过匹配他们就能准确的把内容分发到指定位置,对于父组件中没有指定name DOM,它就会被放置在子组件中匿名 slot 的位置。

注意事项

避免片段实例(Fragment Instance)

不这么写模板:

<div>root node 1</div>
<div>root node 2</div>

推荐这么写:

<div>
  I have a single root node!
  <div>node 1</div>
  <div>node 2</div>
</div>

因为在使用 template 选项时,模板的内容将替换实例的挂载元素。因而推荐模板的顶级元素始终是单个元素。

下面几种情况会让实例变成一个片断实例:

  • 模板包含多个顶级元素。
  • 模板只包含普通文本。
  • 模板只包含其它组件(其它组件可能是一个片段实例)。
  • 模板只包含一个元素指令,如 <partial> 或 vue-router 的 <router-view>。
  • 模板根节点有一个流程控制指令,如 v-if 或 v-for。
<!-- 不可以,因为没有根元素 -->
<example v-show="ok" transition="fade"></example>

<!-- props 可以 -->
<example :prop="someData"></example>

<!-- 流程控制可以,但是不能有过渡 -->
<example v-if="ok"></example>

那么为什么说要避免片段实例呢?

  • 无法通过 this.$el 获取组件内的顶级节点
  • 组件元素上的非流程控制指令,非 prop 特性和过渡将被忽略

避免使用prop 的.sync 父子组件间双向绑定

goodbye.once
goodbye.sync

在即将发布的 Vuejs 2.0中 .once, .sync 修饰符已经确认被废弃
props 会变为单向绑定,子组件不能直接操作父组件的数据属性,应当使用事件$emit 来进行组件间数据的通信

总结

以上讲了一些基础的Vue组件的功能,使用Vue开发SPA还的有重要的路由Vue-router和Flux的Vue实现Vuex,在实际开发中还需要了解Vue的指令、过滤器、生命周期等,结合Vue的文档也能很好理解,也推荐在github 通过 vue-awesome看一写优秀的第三方组件和插件的代码,相信能增长不少Vue开发的经验。

More

官网:http://vuejs.org/
论坛:http://forum.vuejs.org/
资源:https://github.com/vuejs/awesome-vue

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容