(1)基本示例

Vue组件示例

        /* 先注册组件,定义一个名为button-component的新组件 */
Vue.component('button-component',{
data:function(){
return {
count:0
}
},
template:'<button v-on:click="count++">您点击了{{count}}次</button>'
})

组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <button-counter>。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:

<div id="component_area">
<button-component></button-component>
</div>

/* 再实例化,构建组件模板 */
var component_area = new Vue({
el:"#component_area"
});

因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。仅有的例外是像 el这样根实例特有的选项。

(2)组件的复用

可以将组件进行任意次数的复用:

<div id="component_area">
<button-component></button-component>
<button-component></button-component>
<button-component></button-component>
<button-component></button-component>
</div>

注意:①当点击按钮时,每个组件都会各自独立维护它的 count。因为每用一次组件,就会有一个新实例被创建。

②data必须是一个函数

当我们定义这个 <button-counter> 组件时,你可能会发现它的 data 并不是像这样直接提供一个对象:

data: {
count: 0
}

取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

data: function () {
return {
count: 0
}
}

如果 Vue 没有这条规则,点击一个按钮就可能会像如下代码一样影响到其它所有实例。如下所示

var start_count = {count:0};
/* 先注册组件,定义一个名为button-component的新组件 */
Vue.component('button-component',{
data:function(){
return start_count;
},
template:'<button v-on:click="count++">您点击了{{count}}次</button>'
})

demo:

    <div id="component_area">
<button-area></button-area>
<button-area></button-area>
<button-area></button-area>
</div>
<script type="text/javascript">
/* 1、注册组件 */
Vue.component('button-area',{
data:function(){
return {
count:0
}
},
template:"<button @click='count++'>您点击了{{count}}次</button>"
})
/* 2、实例化,构建组件模板 */
new Vue({
el:"#component_area"
})
</script>

(3)组件的组织

通常一个应用会以一棵嵌套的组件树的形式来组织:

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的:

vue.component(my-component-name,{
...
})

全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。到目前为止,关于组件注册你需要了解的就这些了,如果你阅读完本页内容并掌握了它的内容,推荐再回来把组件注册读完。

(4)通过prop向子组件传递数据

早些时候,我们提到了创建一个博文组件的事情。问题是如果你不能向这个组件传递某一篇博文的标题或内容之类的我们想展示的数据的话,它是没有办法使用的。这也正是 prop 的由来。

prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:

Vue.component('blog-title',{
props:[title],
template:"<h3>{{title}}</h3>"
})

一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现能够在组件实例中访问这个值,就像访问 data 中的值一样。一个 prop 被注册之后,就可以像这样把数据作为一个自定义特性传递进来:

<h-component title="博客分类1"></h-component>
<h-component title="博客分类2"></h-component>
<h-component title="博客分类3"></h-component>

然而在典型应用中,在 data 里一般有一个博文的数组:

<div class="h_area">
<h-component v-for="info in infos" v-bind:title="info.name"></h-component>
</div>
/* 1、注册组件 */
Vue.component('h-component',{
props:['title'],
template:'<h3>{{title}}</h3>'
});
/* 2、实例化,构建组件模板 */
new Vue({
el:".h_area",
data:{
infos:[
{name:"博客列表1"},
{name:"博客列表2"},
{name:"博客列表3"}
]
}
});

如上所示,你会发现我们可以使用 v-bind 来动态传递 prop。这在你一开始不清楚要渲染的具体内容,比如从一个 API 获取博文列表的时候,是非常有用的。到目前为止,关于 prop 你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,推荐再回来把 prop 读完。

(4)单个根元素

先来简单回顾下组件

Start:

<div class="blog_area">
<blog-info title="博客文章1"></blog-info>
<blog-info title="博客文章2"></blog-info>
<blog-info title="博客文章3"></blog-info>
</div>
Vue.component('blog-info',{
props:['title'],
template:"<h3>{{title}}</h3>"
});
new Vue({
el:".blog_area"
});

接下来将数据放到数组中

<div class="blog_area">
<blog-info v-for="blog in blogs" :title="blog.name" :id="blog.id"></blog-info>
</div>
Vue.component('blog-info',{
props:['id','title'],
template:"<h3>{{id}}</h3><h4>{{title}}</h4>"
});
new Vue({
el:".blog_area",
data:{
blogs:[
{id:,name:"博客文章1"},
{id:,name:"博客文章2"},
{id:,name:"博客文章3"}
]
}
})

结果:

注意:此时发现一个问题,即组件模板中的h4渲染不出来,控制台也没报错,调试后发现,将其嵌套到h3里才可以正常渲染出来

Vue.component('blog-info',{
props:['id','title'],
template:"<h3>{{id}}<h4>{{title}}</h4></h3>"
});

End

当构建一个 <blog-post> 组件时,你的模板最终会包含的东西远不止一个标题和id:

<h3>{{id}}<h4>{{title}}</h4></h3>

然而如果你在模板中尝试这样写,Vue 旧版一般会报错,并解释道every component must have a single root element (每个组件必须只有一个根元素)。

解决方案:可以将模板的内容包裹在一个父元素内,来修复这个问题

        // 1、注册组件
Vue.component('blog-info',{
props:['id','title','content'],
template:"<h3>{{id}}\
<h4>{{title}}</h4>\
<div v-html='content'></div>\
</h3>"
});
// 2、实例化,构建组件模板
new Vue({
el:".blog_area",
data:{
blogs:[
{id:,name:"博客文章1",content:"博客1文章内容信息content..."},
{id:,name:"博客文章2",content:"博客2文章内容信息content..."},
{id:,name:"博客文章3",content:"博客3文章内容信息content..."}
]
}
})

当组件变得越来越复杂的时候,我们的博文不只需要标题和内容,还需要发布日期、评论等等。为每个相关的信息定义一个 prop 会变得很麻烦,例如:

<div class="blog_area">
<blog-info
v-for="blog in blogs"
:title="blog.name"
:id="blog.id"
:content="blog.content"
:date="blog.date"
></blog-info>
</div>
        // 1、注册组件
Vue.component('blog-info',{
props:['id','title','content','date'],
template:"<div>\
<h3>id为:{{id}}</h3>\
<h4>标题为:{{title}}</h4>\
内容:<div v-html='content'></div>\
时间:<span v-html='date'></span>\
</div>"
});
// 2、实例化,构建组件模板
new Vue({
el:".blog_area",
data:{
blogs:[
{id:,name:"博客文章1",content:"博客1文章内容信息content...",date:"2019.02.10"},
{id:,name:"博客文章2",content:"博客2文章内容信息content...",date:"2019.03.10"},
{id:,name:"博客文章3",content:"博客3文章内容信息content...",date:"2019.04.10"}
]
}
})

结果:

重构组件:所以是时候重构一下这个 <blog-info> 组件了,让它变成接受一个单独的 blog prop:

<div class="blog_area">
<blog-info
v-for="blog in blogs"
:blog="blog"
></blog-info>
</div>
Vue.component('blog-info',{
props:['blog'],
template:"<div>\
<h3>id为:{{blog.id}}</h3>\
<h4>标题为:{{blog.name}}</h4>\
内容:<div v-html='blog.content'></div>\
时间:<span v-html='blog.date'></span>\
</div>"
});

上述的这个和一些接下来的示例使用了 JavaScript 的模板字符串来让多行的模板更易读。它们在 IE 下并没有被支持,所以如果你需要在不 (经过 Babel 或 TypeScript 之类的工具) 编译的情况下支持 IE,请使用折行转义字符取而代之。

现在,不论何时为 blog对象添加一个新的属性,它都会自动地在 <blog-info> 内可用。

(5)监听子组件事件

在开发 <blog-post> 组件时,它的一些功能可能要求和父级组件进行沟通。例如可能会引入一个可访问性的功能来放大博文的字号,同时让页面的其它部分保持默认的字号。

在其父组件中,可以通过添加一个 postFontSize 数据属性来支持这个功能:

    new Vue({
el:".blog_area",
data:{
blogs:[
{id:,name:"博客文章1",content:"博客1文章内容信息content...",date:"2019.02.10"},
{id:,name:"博客文章2",content:"博客2文章内容信息content...",date:"2019.03.10"},
{id:,name:"博客文章3",content:"博客3文章内容信息content...",date:"2019.04.10"}
],
blogFontSize:1
}
})

它可以在模板中用来控制所有博文的字号:

<div class="blog_area" :style="{ fontSize: blogFontSize + 'em' }">
<blog-info
v-for="blog in blogs"
:blog="blog"
v-on:enlarge-text="blogFontSize += 0.1"
></blog-info>
</div>

现在我们在每篇博文正文之前添加一个按钮来放大字号:

        Vue.component('blog-info',{
props:['blog'],
template:'\
<div><h3>id为:{{blog.id}}</h3>\
<h4>标题为:{{blog.name}}</h4>\
内容:<div v-html="blog.content"></div>\
时间:<span v-html="blog.date"></span><br>\
按钮:<button>点击放大</button>\
</div>\
'
});

问题是这个按钮不会做任何事:

当点击这个按钮时,需要告诉父级组件放大所有博文的文本。幸好 Vue 实例提供了一个自定义事件的系统来解决这个问题。父级组件可以像处理 native DOM 事件一样通过 v-on 监听子组件实例的任意事件:

<div id="blog-posts-events-demo" style="display: none;">
<div :style="{ fontSize: postFontSize + 'em' }">
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>
</div>
</div>

同时子组件可以通过调用内建的 $emit 方法 并传入事件名称来触发一个事件:

        // 1、注册组件
Vue.component('blog-info',{
props:['blog'],
template:'\
<div><h3>id为:{{blog.id}}</h3>\
<h4>标题为:{{blog.name}}</h4>\
内容:<div v-html="blog.content"></div>\
时间:<span v-html="blog.date"></span><br>\
按钮:<button v-on:click="$emit(\'enlarge-text\')">点击放大</button>\
</div>\
'
});

有了这个 v-on:enlarge-text="postFontSize += 0.1" 监听器,父级组件就会接收该事件并更新 postFontSize 的值。

①使用事件抛出一个值

有的时候用一个事件来抛出一个特定的值是非常有用的。例如我们可能想让 <blog-info> 组件决定它的文本要放大多少。这时可以使用 $emit 的第二个参数来提供这个值:

按钮:<button v-on:click="$emit(\'enlarge-text\',0.1)">点击放大</button>\

然后当在父级组件监听这个事件的时候,可以通过 $event 访问到被抛出的这个值:

<blog-post
...
v-on:enlarge-text="postFontSize += $event"
></blog-post>

或者,如果这个事件处理函数是一个方法:

<blog-post
...
v-on:enlarge-text="onEnlargeText"
></blog-post>

那么这个值将会作为第一个参数传入这个方法:

methods: {
onEnlargeText: function (enlargeAmount) {
this.blogFontSize += enlargeAmount
}
}

②在组件上使用v-model

首先,写个简单案例测试下组件里是否可以包含表单输入框选项

测试Start:

    <!-- 组件上使用v-model -->
<div class="input_area">
<form>
<input-component value="我是默认值1"></input-component>
<input-component value="我是默认值2"></input-component>
</form>
</div>
// 1、注册组件
Vue.component('input-component',{
props:['value'],
template:"\
<div><input type='text' placeholder='请输入名称' v-model='value'>\
<p>输入数据为:{{value}}</p>\
</div>\
"
});
// 2、实例化,构建组件模板
new Vue({
el:".input_area"
})

结果:

End

接下来依次分析下

自定义事件也可以用于创建支持 v-model 的自定义输入组件

<input type="text" v-model="searchText1"><span>输入:{{searchText1}}</span>

data中:
searchText1:"默认值1"

上面写法等价于

<input type="text" v-bind:value="searchText2" v-on:input="searchText2 = $event.target.value">
<span>输入为{{searchText2}}</span> data中:
searchText2:'默认值2'

当用在组件上时,v-model 则会这样:

<input-component 
v-bind:value="searchText3"
v-on:input="searchText3=$event"
></input-component>

为了让它正常工作,这个组件内的 <input> 必须:

  • 将其 value 特性绑定到一个名叫 value 的 prop 上
  • 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
Vue.component('input-component',{
props:['value'],
template:'\
<div><input type="text" placeholder="请输入名称" v-bind:value="value" v-on:input="$emit(\'input\',$event.target.value)">\
<p>姓名输入数据为:{{value}}</p>\
</div>\
'
});

现在 v-model 就应该可以在这个组件上完美地工作起来了:

<input-component v-bind:value="searchText3" v-on:input="searchText3=$event"></input-component>
||
等价于:
||
<input-component v-model="searchText3"></input-component>

到目前为止,关于组件自定义事件你需要了解的大概就这些了,如果阅读完本页内容并掌握了它的内容,推荐再回来把自定义事件读完。

(6)通过插槽分发内容

和 HTML 元素一样,我们经常需要向一个组件传递内容,像这样:

<alert-box>
发生错误哦
</alert-box>

可能会渲染出这样的东西:

幸好,Vue 自定义的 <slot> 元素让这变得非常简单:

        Vue.component('alert-box',{
template:'<div class="alert_box_area">\
<strong>Error!!!</strong>\
<slot></slot>\
</div>\
'
});
new Vue({
el:".alert_area"
})

如你所见,只要在需要的地方加入插槽就行了——就这么简单!到目前为止,关于插槽你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,推荐你再回来把插槽读完。

(7)动态组件

有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里:

上述内容可以通过 Vue 的 <moving-area> 元素加一个特殊的 is 特性来实现:

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<moving-area v-bind:is="currentTabComponent"></moving-area>

在上述示例中,currentTabComponent 可以包括

  • 已注册组件的名字,或
  • 一个组件的选项对象

你可以在这里查阅并体验完整的代码,或在这个版本了解绑定组件选项对象,而不是已注册组件名的示例。到目前为止,关于动态组件你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,推荐再回来把动态和异步组件读完。

(8)解析DOM模板时的注意事项

先来看个正常解析案例:

Start:

<div class="dom_area">
<p-component
v-for="info in infos"
:info="info"
></p-component>
</div>
Vue.component('p-component',{
props:['info'],
template:"<p>{{info}}</p>"
})
new Vue({
el:".dom_area",
data:{
infos:['展示信息1','展示信息2','展示信息3']
}
})

代码结构正确解析

End

接下来换成table

<div class="dom_area">
<table>
<tr-component></tr-component>
</table>
</div>
Vue.component('tr-component',{
template:"<tr><td>单元格1</td><td>单元格2</td></tr>"
})
new Vue({
el:".dom_area"
})

渲染结果:

有些 HTML 元素,诸如 <ul><ol><table> 和 <select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li><tr> 和 <option>,只能出现在其它某些特定的元素内部。这会导致我们使用这些有约束条件的元素时遇到一些问题,如上所示。自定义组件 <tr-component> 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is 特性给了我们一个变通的办法:

<table border="">
<tr is="tr-component"></tr>
</table>

此时,tr标签可以正确渲染到table里

需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的:

到这里,你需要了解的解析 DOM 模板时的注意事项——实际上也是 Vue 的全部必要内容,大概就是这些了。恭喜你!接下来还有很多东西要去学习,不过首先,我们推荐你先休息一下,试用一下 Vue,自己随意做些好玩的东西。如果你感觉已经掌握了这些知识,我们推荐你再回来把完整的组件指南,包括侧边栏中组件深入章节的所有页面读完。

.

vue之基础---组件基础的更多相关文章

  1. Vue单文件组件基础模板

    背景 相信大家在使用Vue开发项目时,基本都是以单文件组件的形式开发组件的,这种方式好处多多: 1.代码集中,便于开发.管理和维护 2.可复用性高,直接将vue文件拷贝到新项目中 我暂时就想到这两点, ...

  2. vue基础——组件基础

    一.基本示例 这里有一个Vue组件的示例: // 定义一个名为 button-counter 的新组件 main.js Vue.component('button-counter', { data: ...

  3. Ext JS 6学习文档-第3章-基础组件

    Ext JS 6学习文档-第3章-基础组件 基础组件 在本章中,你将学习到一些 Ext JS 基础组件的使用.同时我们会结合所学创建一个小项目.这一章我们将学习以下知识点: 熟悉基本的组件 – 按钮, ...

  4. 小程序开发-基础组件icon/text/progress入门

    小程序的基础组件--基础内容 基础内容分为三大组件: 1. icon--图标 index.wxml <view class="group"> <block wx: ...

  5. Vue组件基础用法

    前面的话 组件(Component)是Vue.js最强大的功能之一.组件可以扩展HTML元素,封装可重用的代码.根据项目需求,抽象出一些组件,每个组件里包含了展现.功能和样式.每个页面,根据自己所需, ...

  6. Vue组件基础

    <!DOCTYPE html><html>    <head>        <meta charset="utf-8">      ...

  7. 前端框架之Vue(9)-组件基础&vue-cli

    组件基础 基本示例 这里有一个 Vue 组件的示例: <!DOCTYPE html> <html lang="en"> <head> <m ...

  8. 从0开始做一个的Vue图片/ 文件选择(上传)组件[基础向]

    原文:http://blog.csdn.net/sinat_17775997/article/details/58585142 之前用Vue做了一个基础的组件 vue-img-inputer ,下面就 ...

  9. Vue学习计划基础笔记(六) - 组件基础

    组件基础 目标: 掌握组件的构建方式 掌握如何复用组件.父子组件如何传值.如何向父组件发送消息 掌握如何通过插槽分发内容 了解解析dom模板时的注意事项 了解动态组件 组件 组件理解起来大概上就和ph ...

随机推荐

  1. ppt五种经典字体组合

    在做ppt中常常为使用哪种字体而头疼,如今将ppt的经典字体附上.希望对大家有帮助 五种经典的字体组合 标题字体 正文字体 使用场合 方正综艺简体 微软雅黑 课题汇报.咨询报告.学术研讨等正式场合 方 ...

  2. HNOI模拟 Day3.23

    一.拓扑(top)[ 题目描述]:给你一个有向二分图,求他的拓扑序列的个数.[ 输入]:第一行两个数 N,M,表示点数和边数.接下来 M 行每行两个数 a,b,表示 a 向 b 有一条有向边.[ 输出 ...

  3. Error Handling Functions(微软对于出错的情况下提供的所有函数,比如SetThreadErrorMode,SetErrorMode,SetLastErrorEx,FatalAppExit,CaptureStackbackTrace)

    The following functions are used with error handling. Function Description Beep Generates simple ton ...

  4. Opencv+Zbar二维码识别(一维码校正)

    一维码由一组规则排列的黑色线条.白色线条以及对应的字符组成.对倾斜的(没有严重形变)一维码的角度校正,可以根据其黑白相间.排列规则的特点,计算傅里叶频谱,通过傅里叶频谱中直线的倾斜角度计算空间域图像一 ...

  5. MySQL:目录

    ylbtech-MySQL:目录 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   作者:ylbtech出处:http://ylbtech ...

  6. urllib2.urlopen超时未设置导致程序卡死

    没有设置timeout参数,结果在网络环境不好的情况下,时常出现read()方法没有任何反应的问题,程序卡死在read()方法里,搞了大半天,才找到问题,给urlopen加上timeout就ok了,设 ...

  7. sql时间截取与修改

    --修改日,从1号修改到10号UPDATE CHECKINOUT SET CHECKTIME=DATEADD(DAY,9,CHECKTIME) WHERE YEAR(CHECKTIME)=1970 a ...

  8. java笔记线程两种方式模拟电影院卖票

    public class SellTicketDemo { public static void main(String[] args) { // 创建三个线程对象 SellTicket st1 = ...

  9. 基于PHP自带的mail函数实现发送邮件以及带有附件的邮件功能

    PHPmail函数简介 bool mail ( string $to , string $subject , string $message [, string $additional_headers ...

  10. spring的annotation

    spring容器创建bean对象的方式: 1,使用反射调用无参构造器来创建实例(前提是这个类有无参构造器)(常规方式) 2,通过工厂类获得实例(工厂类实现了接口FactoryBean<?> ...