Vuejs - 组件式开发

初识组件

组件(Component)绝对是 Vue 最强大的功能之一。它可以扩展HTML元素,封装可复用代码。从较高层面讲,可以理解组件为自定义的HTML元素,Vue 的编译器为它添加了特殊强大的功能。所有的 Vue 组件同时也都是 Vue 的实例,因此可以接受相同的选项对象(除了一些特有的选项)并提供相同的生命周期函数。

再来回顾下 你也许不知道的Vuejs - 花式渲染目标元素 中的代码:

123
<div id="app1">  <helloworld/></div>
1234567891011
Vue.component("helloworld", {  template: "<h1>{{ msg }}</h1>",  data () {    return {      msg: "Hello Vue.js!"    }  }})var app1 = new Vue({  el: "#app1"})

上面通过 Vue.component 注册了一个全局组件,然后在 div#app 元素内通过 <helloworld/> 标签直接使用。可以看出,这里就是相当于自定义了一个 HTML 元素 helloworld,它的功能就是输出一个内容为 msg 的 h1 标签。这就是一个基本全局组件的定义方式,当然你也可以注册为局部组件:

12345678910111213
var app2 = new Vue({  el: "#app2",  components: {    ‘helloworld‘: {      template: "<h1>{{ msg }}</h1>",      data () {        return {          msg: "Hello Vue.js!"        }      }    }  }})

无论是全局或者局部注册组件,它跟上一篇中的指令注册是非常相似的。局部注册组件就是在创建 Vue 实例的时候添加一个 components 对象属性,它的键值对就是一个自定义组件,键是组件名,值是创建组建的配置对象参数。当然也可以将组件定义放到单独的文件,然后通过引入的方式,然后添加到components属性中,这个在单文件组件中会具体讲到。

组件间通信

既然说到组件,就不得不说组件间通信了,实际开发中,我们经常需要在不同组件间传递/共享数据,所以实现组件间通信是非常重要的。

组件间关系可以总结为 父子组件 和 非父子组件,自然通信方式也就是这两种了。

父子组件间通信

如上图,在 Vue 中,父子组件的关系可以总结为 props向下传递,事件向上传递。也就是父组件通过 prop 给子组件下发数据,子组件通过 $emit 事件, 给父组件发送数据。先来看个例子:

1234
<div id="app3">  当前输入内容:{{ text }}<br>  <com-input :text="text" v-on:change="handleChange"/></div>
1234567891011121314151617181920212223242526272829303132333435
Vue.component(‘com-input‘, {  props: {    text: {      type: String,      default: "请输入"    }  },  template: ‘<input v-on:change="handleChange" v-model="msg"/>‘,  data () {    return {      // 这里定义为 input 的 v-model绑定值      msg: this.text    }  },  methods: {    // 当input值变化时,执行函数,通过 $emit change 事件,    // 父级组件通过 v-on:change 来监听此事件,执行相关操作    handleChange (e) {      this.$emit(‘change‘, this.msg)    }  }})var app3 = new Vue({  el: "#app3",  data () {    return {      text: ‘Hello Vue.js‘    }  },  methods: {    handleChange (val) {      this.text = val    }  }})

原理解析:上面的代码中,先通过 Vue.component 定义了 com-input 组件,给它添加了 props 属性,用来接收父级通过属性传递的属性数据 text,这里 text 是个对象,含有 type - 属性值类型 和 default - 默认值 两个属性。当然 props 也可以为所有从父级接受的属性数组,有关 props 基础知识请直接阅读 官方文档。然后将初始值赋值给了 data 中的 msg,该子组件的模板是个 input,通过 v-model 实现 input的值 和 msg 的双向绑定,当input值变化时,通过 this.$emit(‘change‘, this.msg),发出 change 事件,同时将当前值作为监听器回调参数,这样父级组件就可以通过 v-on:change 来监听此事件,获取修改后的值,执行相关操作了。

虽然这段代码同时实现了上述图片中的 父 -> 子 和 子 -> 父 通信流程,但是代码还是比较繁琐的,单纯实现单个数据的循环传递,就需要父子组件同时监听改变事件,执行监听回调函数,是不是太麻烦了。要是能直接修改 props 中的 text 值就好了,实践证明,这是不行的,因为直接修改,会报下面错误(注意只有引入 vue.js 文件才会出现,因为 vue.min.js 文件移除了 [Vue warn] 错误提示功能):

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “text”

这个问题,Vue 作者早就想到了,那就是使用 .sync 修饰符。早在 1.x 版本中此功能是一直存在的,但是作者认为它破坏了 单向数据流 的原则,所以 2.0 发布后,就移除了该修饰符,但是后来发现在实际开发中,有很多相关需求, 于是在 2.3.0+ 版本后,又重新引入了 .sync 修饰符,不过内部实现是跟 1.x 版本有区别的,它并没有破坏 单向数据流 原则,实际上内部就是帮我们实现了父级组件监听和修改相关属性值的操作。

使用 .sync 修改后的代码如下:

1234
<div id="app4">  当前输入内容:{{ text }}<br>  <com-input2 v-bind:text.sync="text"/></div>
123456789101112131415161718192021222324252627
Vue.component(‘com-input2‘, {  props: {    text: {      type: String,      default: "请输入"    }  },  template: ‘<input v-on:change="handleChange" v-model="msg"/>‘,  data () {    return {      msg: this.text    }  },  methods: {    handleChange (e) {      this.$emit(‘update:text‘, this.msg)    }  }})var app4 = new Vue({  el: "#app4",  data () {    return {      text: ‘Hello Vue.js‘    }  }})

这次我们只是将子组件的 $emit 事件名修改为 update:text,并删除了父级组件 v-on:change 监听和相关监听回调,并在模板中 v-bind:text 后面添加了 .sync 修饰符,这样就是实现了相同的功能,代码确实精简了很多。实际上 Vue 在编译含有 .sync 修饰符的 v-bind 指令时,会自动实现监听 update 事件的相关代码,也就是:

1
<com-input2 v-bind:text.sync="text"/>

会被扩展为:

1
<com-input2 v-bind:text="text" v-on:update="val => text = val"/>

注意:val => text = val 是箭头函数,关于箭头函数的介绍可以看这里:箭头函数

这样一解析就很好理解了,全部是我们上一节讲到的内容。

非父子组件间通信

如果是两个非父子组件,并且有共同的父级组件,那么它拆解为 子 -> 父 -> 子 的过程,这个就完全可以使用 父子组件间通信 方法实现。如果是多个组件或者不同父组件的组件间通信,这时我们可以借助创建空的 Vue 实例作为事件总线,通过 发布订阅模式 进行数据传递。 代码如下:

1234
<div id="app5">  组件A: <com-a></com-a><br>  组件B: <com-b></com-b></div>
123456789101112131415161718192021222324252627282930313233343536373839404142
var bus = new Vue()Vue.component(‘com-a‘, {  template: ‘<input v-on:change="handleChange" v-model="msg"/>‘,  data () {    return {      msg: ‘Hello Vue.js‘    }  },  methods: {    handleChange() {      bus.$emit(‘a-change‘, this.msg)    }  },  created () {    var me = this    bus.$on(‘b-change‘, function (msg) {      me.msg = msg    })  }})Vue.component(‘com-b‘, {  template: ‘<input v-on:change="handleChange" v-model="msg"/>‘,  data () {    return {      msg: ‘Hello Vue.js‘    }  },  methods: {    handleChange() {      bus.$emit(‘b-change‘, this.msg)    }  },  created () {    var me = this    bus.$on(‘a-change‘, function (msg) {      me.msg = msg    })  }})var app5 = new Vue({  el: ‘#app5‘})

熟悉 发布订阅模式 的同学,应该很容易理解上面这段代码,创建的全局空 Vue 实例 bus 就是用来充当中央事件总线,所有的事件都经过它来触发和传播。

思路解析:在组件 com-a 中,当 input 值发生改变时,通过 bus.$emit(‘a-change‘, this.msg) 来触发修改事件,并将其更新后的值做为参数传递,组件 com-b 通过 bus.$on(‘a-change‘, xxx) 来监听,进行值更新操作,组件 com-b 也是相同原理。

当然在复杂情况下,我们应该考虑使用专门的 状态管理模式,比如 vuex,这个将在后续的文章中讲到。

动态组件

Vue 中还提供了 component 元素,允许我们在实际开发中,通过修改其 is 属性值,来动态切换组件。这个在某些应用场景非常实用,笔者曾经有个需求就是,需要根据参数 type来绘制不同类型的图表,而我的所有图表类型都已经装成了一个独立的组件,所以我只需要依据此特性,通过参数 type 来动态修改元素 component 的属性 is 为对应的组件名称即可。

下面来看示例代码:

1234
<div id="app6">  <button v-on:click="changeType">改变组件</button><br>  <component v-bind:is="currentComp"></component></div>
1234567891011121314151617181920212223242526
var app6 = new Vue({  el: ‘#app6‘,  data () {    return {      type: ‘a‘    }  },  computed: {    currentComp () {      return this.type === ‘a‘ ? ‘com-a‘ : ‘com-b‘;    }  },  components: {    ‘com-a‘: {      template: ‘<h1>我是组件a</h1>‘    },    ‘com-b‘: {      template: ‘<h1>我是组件b</h1>‘    }  },  methods: {    changeType () {      this.type = this.type === ‘a‘ ? ‘b‘ : ‘a‘;    }  }})

运行上面代码,点击改变组件按钮,就可以轻松的实现组件 com-a 和 com-b 的动态切换了,是不是很酷?赶紧动手尝试下吧。

原文地址:https://www.cnblogs.com/kkdn/p/9222654.html

时间: 2024-10-09 06:35:58

Vuejs - 组件式开发的相关文章

前端全栈架构,组件式开发,响应式开发,全栈工程师架构,用户界面架构,企业级架构项目实战

我本是一名文科专业半路出家的前端开发人员,从最初只会切图和写CSS.Html到现在会写点JS,一路坑坑洼洼,也是经历了很多,从2010年开始就用WordPress开设了自己的博客,虽然内容零零散散的并不多,但是多多少少也留下了时光的缩影,一直希望自己有一个自留地.用Node.js做服务端替换WordPress是去年的一个想法,由于一直腾不出时间,所以拖到了现在.当然了WordPress作为全球用户量最广的开源博客程序,易用性等诸多好处无可厚非,光自己的博客在过去几年就用了很多套模板,也用它做过很

基于TypeScript的FineUIMvc组件式开发(简介)

不熟悉FineUI的可以访问其官方网站(http://www.fineui.com),在这里我从我的个人角度说一下FineUI,FineUI有多个版本,但主要基于2种架构,一种是基于Asp.net WebForm,别一种是基于Asp.net Mvc. 在WebForm版本下,虽然FineUI是一个前端构架,但在一些常规简单项目中几乎不用写JS代码,除了首次请求页面,后续的操作都是基于Ajax的,而JS代码都是由服务器端动态生成,并放到客户端执行,这也是FineUI的一大特点.了解WebForm的

注入式类的写法,解耦,组件式开发,沙箱

沙箱(网络编程虚拟执行环境) Sandboxie(又叫沙箱,沙盘)即是一个虚拟系统程序,允许你在沙盘环境中运行浏览器或者其他应用. 因此运行会产生的变化可以随后删掉. 它创造了一个类似沙盒的独立作业环境,在其中内部运行并不会对硬盘产生永久的影响. 其为一个独立的 虚拟环境,可用以测试不受信任的应用程序或上网行为. 沙箱是一种按照安全策略限制程序行为的执行环境. 早期主要用于测试可疑软件等,比如黑客们为了试用某种病毒或者不安全产品,往往可以将它们在沙箱环境中运行. 经典的沙箱系统的实现途经一般是通

基于TypeScript的FineUIMvc组件式开发(开头篇)

了解FineUIMvc的都知道,FineUIMvc中采用了大量的IFrame框架,对于IFrame的优缺点网上也有很多的讨论,这里我要说它的一个优点"有助于隔离代码逻辑",这也是FineUIMvc官网对它的描述.IFrame在网页上下文中是完全独立的,这样也就不存在了样式及脚本之间的冲突问题.但由于IFrame与上下文之间是隔离的,在交互上也给我们带来了一些不便. 在接下来的文章中,我将主要介绍如何使用TypeScript对FineUIMvc进行组件式开发,而这里的组件就是基于IFra

PIE SDK组件式开发综合运用示例

1. 功能概述 关于PIE SDK的功能开发,在我们的博客上已经分门别类的进行了展示,点击PIESat博客就可以访问,为了初学者入门,本章节将对从PIE SDK组件式二次开发如何搭建界面.如何综合开发进行详细的讲解. 2. 功能实现 2.1.界面搭建 最终的界面如下图所示: 图1最终结果图 2.1.1 新建项目 选择“Window窗体应用程序”,设置程序的名称和保存路径即可.(新建完成后可以将程序的窗体名称右键重命名为“FormMain”,,将窗体界面的属性的Text设置名称为“PIE应用程序”

组件式开发 webapp全站之第一章

1-1课程介绍 略1-2课程安排 课程安排分为两个方面:开发流程和技术实现 1-2-1开发流程 为什么要说流程 每个流程要做什么 各个环节易出现什么问题 问题定责 1-2-2技术实现 技术规划,选型 设计易扩展的开发方案 开发各种图表组件1-3WEB项目开发流程介绍 1-3-1为什么要说开发流程 1.可以提升开发效率 2.防止背锅 1-3-2开发流程的环节划分 开发流程划分为三个环节:开发前,开发中,开发后 1)开发前 产品功能设计 产品经理 产出:产品需求文档 视觉/交互设计 美工 产出:视觉

组件式开发

为什么要做组件化? 无论前端也好,后端也好,都是整个软件体系的一部分.软件产品也是产品,它的研发过程也必然是有其目的.绝大多数软件产品是追逐利润的,在产品目标确定的情况下,成本有两个途径来优化:减少部署成本,提高开发效率. 减少部署成本的方面,业界研究得非常多,比如近几年很流行的“去IOE”,就是很典型的,从一些费用较高的高性能产品迁移到开源的易替换的产品集群,又比如使用Linux + Mono来部署.net应用,避开Windows Server的费用. 提高开发效率这方面,业界研究得更多,主要

[转] Vue + Webpack 组件式开发(练习环境)

前言 研究了下别人的 vue 多页面框架, 都是直接复制 package.json 文件,然后在本地 npm install 一下即可, 或者使用官网 vue-cli 工具生成一个项目, 觉得这样虽然看的懂, 但是记不住, 因此有必要从零开始搭建一个使用 .vue 作为组件的项目练习一下, 因此有了这个项目. 既然使用了 .vue 组件, 就不能像之前使用 jQuery 一样把 vue.js 引入页面中, 而是使用配套的 webpack + babel + 各种 loader 工具编译 .vue

Agile.Net 组件式开发平台 - 报表组件类库

Agile.Report.dll 文件为平台报表支持库,基于FasstReport.Net扩展重写,提供报表打印.报表预览.报表设计.自定义报表数据源等二次开发功能. 示例   //声明报表对象 var report = new Agile.Report.ReportLib(); //添加查询参数 report.AddParameter("Code", "1023"); ////添加自定义数据源 //report.AddDataSource(DataSource);