vue的学习曲线不是很陡(相比其它框架,如anglarjs),官方文档比较全面,分为基础篇和高级篇。我们刚开始学习的时候,肯定像引用jquery那样,先把vue的js引进来,然后学习基础内容。如果仅仅停留在基础内容,没有学习vue组件的话,我觉得也就没有什么意思了。vue的核心思想——组件,是一个很好的东西,它提供了功能复用。

 1、单文件组件

        所谓单文件组件,顾名思义,一个vue格式的文件就是一个组件。好比python和js的模块,文件即模块。vue组件带有自己的模板,可以理解为视图,也带有自己数据及逻辑。数据可以从外部来,通过Prop接收。用图形表示:

  由此可见,单文件组件就是一个完整而独立的体系。注意,style有个属性scope表示仅作用于当前组件。wpf当中的控件,有自己的xaml(视图),逻辑,可以外部绑定数据源。我觉得vue组件类似wpf中的用户控件。因为用户控件组合了基础的控件,比如Button、TextBlock等等。用户控件可直接当成一个独立的组件使用。它和vue组件一样,都是从外部获取特定的信息,然后构建自己内部的数据以及逻辑。其实组件体现的是面向对象中的“封装”思想。

2、动态组件&异步加载

     有时候读了官方的文档,还是不明白,这时候就需要上网搜搜相关资料。好比《圣经》或者《道德经》中的经文是需要慢慢揣摩和体会的。当然vue的动态组件、以及组件的异步加载也是需要在实践当中慢慢体会的。下来分享一个我在项目中使用的例子:

在后台管理页面中,编辑、增加一条信息,这时候需要在弹出页面中操作。因此,我就封装了一个弹出模态框(带有遮罩效果)的组件。而编辑页面是另外的一个组件。所以,需要把编辑页面的组件“送到”弹出框的组件中呈现。有点像“装饰器模式”,不要原生态地呈现编辑组件,而是把它包装一番,再呈现,如下图:

后台管理中像这样的编辑页面非常多,所以弹出框组件的意义就在这,复用。我上面说了需要把“编辑软件资源”的组件,送到弹出框组件显示。如何送呢?其实也不难。我把这个组件作为弹框组件的子组件。那么这个弹框组件有很多个编辑组件。现在问题来了,如何控制它们显示?当我点击“编辑软件资源”的时候,弹出对应的页面,当我点击编辑新闻的时候,它要弹出新闻的页面,难道我要控制组件的显示隐藏吗?这个情况有点像“Tab”,任何时候,只能呈现一个TabItem,那么其它的只能隐藏掉。好了,我们也可以这么做。还有另外一个问题,我们如何导入这些组件,一次性import多个组件,貌似也没有什么问题。这会不会影响页面加载的性能呢?我想肯定会。

我想到了秦腔中的“变脸”,对,这个很有意思,一个人通过变脸可以扮演多个人。和演员一样,比如最近的一个电视剧中景甜扮演了“奉剑”和“千湄”两个角色。vue里面的动态组件就是如此,一个组件总是“扮演”各种组件。异步加载,当我需要用你的时候,再去import,这显然是合理的。说了这么多,我们看看代码:

 <template>
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container" :style="{width:width,height:height}"> <div class="modal-header">
<slot name="header">
{{title}}
</slot>
<button class="modal-default-button" @click="close">
X
</button>
</div> <div class="modal-body" :style="{height:bodyHeight,width:bodyWidth}">
<slot name="body">
<component :is="currentComponent" @close="close" :id="id"></component>
</slot>
</div> </div>
</div>
</div>
</transition>
</template> <style scoped>
.modal-mask {
position: fixed;
z-index: 9998;
top: 50%;
left: 50%;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
display: table;
transform: translateX(-50%) translateY(-50%);
transition: opacity .3s ease;
} .modal-wrapper {
display: table-cell;
vertical-align: middle;
} .modal-container {
margin: 0px auto;
padding: 20px 30px;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, .33);
transition: all .3s ease;
font-family: Helvetica, Arial, sans-serif;
} .modal-header h3 {
margin-top: 0;
color: #42b983;
} .modal-body {
margin: 10px 0;
overflow-y: auto
} .modal-default-button {
float: right;
background: none;
border: none;
cursor: pointer;
} /*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/ .modal-enter {
opacity: 0;
} .modal-leave-active {
opacity: 0;
} .modal-enter .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
</style> <script>
export default {
props: {
title: {
type: String
},
width: {
type: String,
required: false,
default: '30%'
},
height: {
type: String,
required: false,
default: '65%'
}, currentComponent: {
type: String,
required: true
},
id: {
type: Number,
default: 0
}
},
components: {
newsItem(resolve) {
require(['../Admin/newsItem'], resolve)
},
softwareItem(resolve) {
require(['../Admin/softwareItem'], resolve)
}
},
data() {
return {
bodyHeight: '98%',
bodyWidth: '100%'
}
},
methods: {
close(type) {
if (type)
this.$emit('close', type);
else
this.$emit('close');
}
}
}
</script>
Props中接收 currentComponent,要呈现哪个组件,交给调用方,谁调用我,谁就必须告诉我,该显示哪个子组件。

3、组件通信

    组件间通信问题,是一个普遍问题。组件再独立也得和其它组件协同完成任务吧。没有一个组件能完成所有事情常见的那就父子之间的通信以及兄弟之间的通信。有没有父组件引发了一个事件,由子组件来处理呢?貌似没有。如果有的话,就是父组件更改了Props中属性的值。如果子组件非要在更改值
的时候,作出某些处理的话,那么就用Watch了。

  props: ["pageIndex", "pageSize", "total", "groups", "skin"],
watch: {
total(val, oldVal) {
if (val != oldVal) {
this.render();
}
},
}

这个watch监视的是total(总页数),是分页组件监视Props中的total,一旦total改变,那么分页组件需要render,调用render方法重新渲染自己。

 子组件触发事件,父组件监听,这是非常常见的。比如弹出框组件中的关闭事件,分页组件中的 pageHandler 分页事件,这些都要父组件来处理,子组件通过 $emit,这是vue全局的方法,哪个组件都可以用。父组件必须监听pageHandler事件:

 <ym-pager v-if="total" :page-index="pageIndex" :page-size='pageSize' :total='total' :groups="5" @pageHandler="loadData"></ym-pager>

兄弟之间的通信,如何解决呢?网上一搜,基本上都是给一个总线级别的组件,这个组件就是用来通讯的,谁需要发布事件,就往这里发,谁需要处理,那么就监听相关事件。理论上可以实现,但是我在实践的过程中,始终没有成功,不知道为什么。还有一种思路,

通过vuex实现,事件发布方,更改vuex中的某个状态值,那么监控方发现这个状态有变化的时候,就去处理事件。vuex是一个集中式的状态管理器。“天下有变,则命一上将将荆州之军以向宛、洛。。。。。。”,《隆中对》反映了蜀汉对天下大势要密切监视,一旦

发生了变化,就要采取行动了。兄弟之间的通信,我们项目还真没有用到过,如果需要的同学,可进一步查阅资料,这里仅探讨思路。

4、slot

   这个特别有用,也有意思。插槽,它反映了一种IOC(控制反转)的思想。本来子组件的呈现由自己做决定,可是某些情况下,子组件的某一部分变数很大,需要抽象出来,就用了slot先占着,等父组件调用的时候,再告诉该如何渲染。比如我们有一个table组件,这个组件实现了分页等功能。可是table的表头和表的内容充满着变数,若是由父组件通过Props传递,也可以,就是特别麻烦,传递的东西太多了,而且子组件这边也需要很多处理。大道至简,用slot,简洁。table组件不用那么费劲。调用table的父组件也不用想着如何更好地传递数据了。

  <table class="ym-table table-hover">
<slot name="thead"></slot>
<slot name="tbody"></slot>
</table>

table组件中定义了两个命名slot,看看如何调用:

  <YmTable :page-title="pageTitle" :total="totalCount" :page-size="pageSize" @pager="pager" @newItem="newItem">
<thead slot="thead">
<tr>
<th>序号</th>
<th>软件名称</th>
<th>简介</th>
</tr>
</thead>
<tbody slot="tbody">
<tr v-for="(item,index) in items" :key="item.id">
<td v-text="getIndex(index)"></td>
<td>
{{item.name}}
</td>
<td>
{{item.summary}}
</td>
</tr>
</tbody> </YmTable>

5、vue生命周期

生命周期是个老生常谈的问题。是个对象,那就总有个生命周期吧。比如.net中Page对象,页面的生命周期,而且这个还是主考官特别爱考的问题。Android的中Activity的生命周期Page和Activity对象的功能有点像,提供用户操作的界面,可以简单地理解为UI。

网上最著名的就是这张图:

这个图,我们大致理解一下,它核心就是如何把VM(虚拟的dom)转换为实际dom,而且在什么时候转换。这里有一点记住就行了,Created的时候,dom还没有被渲染出来,此时不宜操作dom相关的事情。Mounted的时候,做的事情就多了。比如,在mounted的时候,通过layui绑定form的提交事件。

 mounted() {
let that = this; var form = layui.form; //绑定form提交事件 layui.form.on('submit(*)', function (data) { that.summit(); return false;
});
},

再例如,封装了一个Select的组件,在updated的时候,执行select的render:

  updated() {
layui.form.render('select');
},
总之,vue生命周期中,都会留有钩子函数,通过这些才能把我们的业务逻辑注入到Vue对象中,而且得到执行。我们做一件事情,要看准时机,如果时机不对,事倍功半,甚至一败涂地。诸葛亮出山的时机不对啊。

6、实例变量 && $nextTick

  文档中是这么说的:将回调延迟到下次DOM更新循环之后执行。在修改数据之后立即使用这个方法,获取更新后的DOM。很抽象啊,不理解。但是我需要它。我封装了一个YmRichText组件,这个组件里是调用了kindeditor,富文本框。
mounted() {
let that = this;
this.$nextTick(function () {
that.kedit('textarea[name="content"]');
}); },
methods: {
getConent() {
return editor.html();
},
kedit(k) {
let that = this;
window.editor = KindEditor.create(k, {
width: '98%',
height: that.height + 'px',
uploadJson: that.uploadFileUrl,
allowFileManager: false
}); } }

当在mounted的时候,不管怎么样创建的editor对象都为空。所以使用了$nextTick。按理说,不应该啊,模板中有textarea,kindeditor的js和css也加载上了,而且也在mounted的时候调用的。但是反过来想,在$nextTick调用成功,说明在当前周期内,是不会调用kindeditor的方法的。我们的分页组件中,也使用了 $nextTick这个倒好理解,因为在created时候,调用render,render方法中会操作dom,所以只能等下一个周期执行了。

    created() {
this.render();
},
watch: {
total(val, oldVal) {
if (val != oldVal) {
this.render();
}
},
pageIndex(val) {
this.cindex = val;
if (val == 1) {
this.render();
}
}
},
methods: {
render() {
let self = this;
this.$nextTick(function () {
layui.laypage.render({
elem: self.pagerId,
skin: self.cskin,
count: self.total, //总数数
limit: self.pageSize, //每页显示条数
groups: self.cgroups, //连续显示分页数
curr: this.cindex, //当前页
jump: function (obj, first) {
if (!first) self.$emit("pageHandler", obj.curr);
}
});
});
}
}

实例变量多了,比如引用父组件的$parent,引用子组件的$refs,$refs特别有用,比如要执行子组件里的方法或者获取子组件的数据。

 <ym-company-select :oldCompanyId="oldCompanyId" ref="company"></ym-company-select>
this.data.companyId = this.$refs.company.companyId;

以上,就是我探讨的vue组件开发的一些问题。

vue前端开发那些事——vue组件开发的更多相关文章

  1. 每天记录一点:NetCore获得配置文件 appsettings.json vue-router页面传值及接收值 详解webpack + vue + node 打造单页面(入门篇) 30分钟手把手教你学webpack实战 vue.js+webpack模块管理及组件开发

    每天记录一点:NetCore获得配置文件 appsettings.json   用NetCore做项目如果用EF  ORM在网上有很多的配置连接字符串,读取以及使用方法 由于很多朋友用的其他ORM如S ...

  2. amazeui学习笔记二(进阶开发5)--Web 组件开发规范Rules

    amazeui学习笔记二(进阶开发5)--Web 组件开发规范Rules 一.总结 1.见名知意:见那些class名字知意,见函数名知意,见文件名知意 例如(HISTORY.md Web 组件更新历史 ...

  3. vue前端开发那些事——vue开发遇到的问题

    vue web开发并不是孤立的.它需要众多插件的配合以及其它js框架的支持.本篇想把vue web开发的一些问题,拿出来讨论下.  1.web界面采用哪个UI框架?项目中引用了layui框架.引入框架 ...

  4. vue.js原生组件化开发(一)——组件开发基础

    前言 vue作为一个轻量级前端框架,其核心就是组件化开发.我们一般常用的是用脚手架vue-cli来进行开发和管理,一个个组件即为一个个vue页面,这种叫单文件组件.我们在引用组件之时只需将组件页面引入 ...

  5. 如何实现vue前端跨域,proxyTable解决开发环境前端跨域问题

    在开发环境与后端调试的时候难免会遇到跨域问题,很多人说跨域交给后端解决就好了. 其实不然,前端也有很多方法可以解决跨域,方便也快捷. 常见的有nginx转发.node代理. 在vue项目中常用的是pr ...

  6. 小白学习vue第五天(理解使用组件开发,组件第一弹)

    组件怎么从创建到使用? 第一步创建组件构造器对象 感觉个人理解就是创建一个模板,和创建MongoDB数据模板相似 const cpnC = Vue.extend({ template: ` <d ...

  7. 基于GBT28181:SIP协议组件开发-----------第二篇SIP组件开发原理

    原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3937590.html,qq:1269122125. 上一节中讲的S ...

  8. 循序渐进VUE+Element 前端应用开发(20)--- 使用组件封装简化界面代码

    VUE+Element 前端应用,比较不错的一点就是界面组件化,我们可以根据重用的指导方针,把界面内容拆分为各个不同的组合,每一个模块可以是一个组件,也可以是多个组件的综合体,而且这一个过程非常方便. ...

  9. 在Vue前端项目中,附件展示的自定义组件开发

    在Vue前端界面中,自定义组件很重要,也很方便,我们一般是把一些通用的界面模块进行拆分,创建自己的自定义组件,这样操作可以大大降低页面的代码量,以及提高功能模块的开发效率,本篇随笔继续介绍在Vue&a ...

随机推荐

  1. Unix下 五种 I/O模型

    Unix下共有五种I/O模型: 1. 阻塞式I/O  2. 非阻塞式I/O  3. I/O复用(select和poll)  4. 信号驱动式I/O(SIGIO)  5. 异步I/O(POSIX的aio ...

  2. 什么是webhook

    什么是webhook 翻译,原文地址:https://sendgrid.com/blog/webhook-vs-api-whats-difference/ 一.概述 Webhook是一个API概念,并 ...

  3. Mysql 语句单表查询

    一基本查询 -- 创建商品表 CREATE TABLE products( pid INT PRIMARY KEY AUTO_INCREMENT, pname VARCHAR(20), price D ...

  4. RAID独立冗余磁盘阵列

    独立冗余磁盘阵列(Redundant Array OF Independent Disks,RAID)开始于20世纪80年代美国加州大学伯克利分校的一个研究项目,当时RAID被称为廉价冗余磁盘阵列(R ...

  5. Java控制语句——分支、循环、跳转

    分支语句(if语句,switch语句): 循环语句(for,while,do...while); 跳转语句(break,continue,return): 分支语句(if语句,switch语句) if ...

  6. Android -- 读写文件到内部ROM,SD卡,SharedPreferences,文件读写权限

    (内容整理自张泽华教程) 1. 概述 使用文件进行数据存储 首先给大家介绍使用文件如何对数据进行存储,Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过 ...

  7. Linux 设备驱动之 UIO 机制

    一个设备驱动的主要任务有两个: 1. 存取设备的内存 2. 处理设备产生的中断 对于第一个任务.UIO 核心实现了mmap()能够处理物理内存(physical memory),逻辑内存(logica ...

  8. spring3: 基于Schema的AOP

    6.3  基于Schema的AOP 基于Schema的AOP从Spring2.0之后通过“aop”命名空间来定义切面.切入点及声明通知. 在Spring配置文件中,所以AOP相关定义必须放在<a ...

  9. java中int i 会出现i+1i吗

    Java中int是32,范围是-2147483648到2147483647 所以i+1 < i 或者 i-1 > i是会出现的. int i=(int) Math.pow(2, 32); ...

  10. python 爬虫001-http请求过程

    HTTP 请求流程 一次完整的HTTP请求过程从TCP三次握手建立连接成功后开始,客户端按照指定的格式开始向服务端发送HTTP请求,服务端接收请求后,解析HTTP请求,处理完业务逻辑,最后返回一个HT ...