Vue组件

测试代码

创键组件

两种方式:
方法一:使用Vue.extend({})

var component = Vue.extend({
  template: '<div>component</div>'
});
// 里面还可以添加其他的属性

方法二:使用字面量

 var component = {
   template: '<div>component</div>'
}

注册组件

全局注册
语法:

Vue.component('my-component', {
  // 选项
})

示例:

// 创建组件
var component = {template: '<div>component</div>'}
// 全局注册组件

Vue.component('my-component', component);

局部注册

// 创建组件
var component = {template: '<div>component</div>'}
// 在 Vue组件实例内注册component组件,该组件只能在该实例中使用
var vm = new Vue({
            el: '#app',
            components: {
                'mycomponent ': component ,
            }
        })

注意点:

  • HTML 特性是不区分大小写的。所以,当使用的不是字符串模版,camelCased (驼峰式) 命名的 prop 需要转换为相对应的 kebab-case (短横线隔开式) 命名:
Vue.component('child', {
  // camelCase in JavaScript
  props: ['myMessage'],      // 这里使用的是驼峰式命名
  template: '<span>{{ myMessage }}</span>'
})
// 在下面的HTML文件中引用时,需要改为kebab-case的形式,也就是短横线隔开
<child my-message="hello!"></child>

如果你使用字符串模版,则没有这些限制。

注意(谨记):在HTML中,属性是不区分大小写的,例如:class、Class或CLASS都是表示class,因此,当在Vue中使用props向子组件传递数据时,如果props是驼峰式命名,那么在HTML文件中使用时,需要修改为kebab-case(短横线隔开式或称为烤肉串)的形式,否则,Vue将会无法解析

使用props传递数据

Vue.component('child', {
  // 声明 props
  props: ['message'],
  // 就像 data 一样,prop 可以用在模板内
  // 同样也可以在 vm 实例中像“this.message”这样使用
  template: '<span>{{ message }}</span>'
})
// 通过下面这种方式传递数据
<child message="hello!"></child>

动态prop

将父组件的数据通过v-bind绑定到子组件上,与绑定HTML特性是一样的;每当父组件的数据变化都会反映到子组件上

<div>
  <input v-model="parentMsg">
  <br>
  <child v-bind:my-message="parentMsg"></child>
</div>

字面量语法 VS 动态语法

初学者常犯的一个错误是使用字面量语法传递数值:

<!-- 传递了一个字符串 "1" -->
<comp some-prop="1"></comp>

因为它是一个字面 prop,它的值是字符串 "1" 而不是 number。如果想传递一个实际的 number,需要使用 v-bind,从而让它的值被当作 JavaScript 表达式计算:

<!-- 传递实际的 number -->
<comp v-bind:some-prop="1"></comp>

通过v-bind:some-props="1"传递的是一个number,而通过some-prop="1"传递的是一个 字符串

props数据校验

Vue.component("example", {
  props: {
    // 基础类型检测 (`null` 意思是任何类型都可以)
    propA: Number,
    // 多种类型
    propB: [String, Number],
    // 必传且是字符串
    propC: {
      type: String,
      required: true
    },
    // 数字,有默认值
    propD: {
      type: Number,
      default: 100
    },
    // 数组/对象的默认值应当由一个工厂函数返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
});

注意:props会在组件实例创建之前进行校验,所以在default、validator函数里,诸如:data, computedmethods等实例属性都无法使用

非props特性传递

在Vue中,在大多数情况下,传递给组件的值会覆盖组件本身就设定的值,例如传递type=large会覆盖组件上的type=small,且有可能破坏该组件,但是,对于class和style特性在传递时,不会发生覆盖,只会合并,假如组件上class=one,又传递class=two,则最终组件的class= one two

原生事件监听

通过在事件上添加.native可以增加对原生事件的监听,如下:
`<my-component v-on:click.native="doTheThing"></my-component>

.sync修饰符

一般情况下,子组件对props的修改无法更新到父组件中,但是在2.3.0之后的版本中添加了.sync修饰符,可以在子组件上更新props,同时同步到父组件上,如下:
<comp :foo.sync="bar"></comp>
上面这段代码会被扩展为,如下代码:
<comp :foo="bar" @update:foo=" val => bar = val"></comp>
如果子组件需要更新,则按如下方式即可:
this.$emit('update:foo', newValue);

单向数据流

prop绑定数据是单向的,当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。

另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告

使用插槽分发内容(slot)

单个插槽

注意几点:

  1. 当子组件没有slot插槽时,父组件调用子组件时,包含的内容都会丢失
  2. 当父组件调用子组件没有包含内容时,显示slot中的内容

示例1:子组件没有slot插槽时

<div>
  <h1>我是父组件的标题</h1>
  <c-child>
    <p>这是一些初始内容</p>
    <p>这是更多的初始内容</p>
  </c-child>
</div>

// 子组件child的模板,在该组件中没有slot,因此父组件调用子组件时包含的内容不会显示出来
<template id="child">
  <div>
    <h2>我是子组件的标题</h2>
  </div>
</template>

Vue.component("c-child", {
   template: "#child"
});

new Vue({
   el: "#app-1"
});

上面代码输出结果如下:


没有slot的显示效果

当在child组件中添加slot,修改为如下代码:

<template id="child">
  <div>
    <h2>我是子组件的标题</h2>
    <slot></slot>
  </div>
</template>

显示结果如下:

添加slot后,父组件调用子组件时包含的内容显示出来了

示例2:当父组件调用子组件时,没有包含内容,则显示slot中的内容

<div>
  <h1>我是父组件的标题</h1>
  <c-child>
  </c-child>
</div>

// 子组件child的模板,在该组件中没有slot,因此父组件调用子组件时包含的内容不会显示出来
<template id="child">
  <div>
    <h2>我是子组件的标题</h2>
    <slot>显示slot内容</slot>
  </div>
</template>

Vue.component("c-child", {
   template: "#child"
});

new Vue({
   el: "#app-1"
});

如下:


显示slot内容

具名插槽

<slot> 元素可以用一个特殊的属性 name 来配置如何分发内容。多个插槽可以有不同的名字。具名插槽将匹配内容片段中有对应 slot 特性的元素。

也就是说,在子组件中可以为slot通过name属性定义名字,然后在父组件调用子组件的时候,可以通过slot="header"来为子组件中name="header"的slot指定内容,假如指定的name 在子组件中没有找到,那么该内容将会被抛弃

// 子组件模板
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

// 父组件
<app-layout>
  <h1 slot="header">这里可能是一个页面标题</h1>
  <p>主要内容的一个段落。</p>
  <p>另一个主要段落。</p>
  <p slot="footer">这里有一些联系信息</p>
</app-layout>

最终的渲染结果如下:

<div class="container">
  <header>
    <h1>这里可能是一个页面标题</h1>
  </header>
  <main>
    <p>主要内容的一个段落。</p>
    <p>另一个主要段落。</p>
  </main>
  <footer>
    <p>这里有一些联系信息</p>
  </footer>
</div>

该特性非常有用

作用域插槽

作用域插槽是一种特殊类型的插槽,用作一个替换已渲染元素的 (能被传递数据的) 可重用模板。
在子组件中,只需将数据传递到插槽,就像你将 props 传递给组件一样:

<div class="child">
  <slot text="hello from child"></slot>
</div>

在父级中,具有特殊属性 scope 的 <template> 元素必须存在,表示它是作用域插槽的模板。scope 的值对应一个临时变量名,此变量接收从子组件中传递的 props 对象:

<div class="parent">
  <child>
    <template scope="props">
      <span>hello from parent</span>
      <span>{{ props.text }}</span>
    </template>
  </child>
</div>

以上代码渲染结果:

<div class="parent">
  <div class="child">
    <span>hello from parent</span>
    <span>hello from child</span>
  </div>
</div>

一个示例:

image.png

参考:Vue作用域插槽的使用

动态组件

Vue中的动态组件需要指定一个挂载点,在该挂载点之下,可以动态的切换组件

用法:
通过<component v-bind:is="currentView"></component> 来调用组件,当currentView改变时,就切换组件,

实例:

var vm = new Vue({
  el: "#example",
  data: {
     currentView: 'home'
  },
  // 在该实例下的组件
  components: {
      home: { /* home组件 */},
      posts: { /* posts组件 */ },
  }
});

// 当vm.currentView改变时就进行组件切换,组件就在当前位置进行显示
<component v-bind:is="currentView">
  <!-- 组件在 vm.currentview 变化时改变! -->
</component>

在使用动态组件进行切换时,被切换出来的组件会被消除,这样就存在一个问题:当重复的切换组件时,组件不断地被消除,然后又重建,导致性能很差,这时可以使用 keep-alive 来使被切换的组件保持在内存中,避免了重新渲染,keep-alive的用法如下:

// 只需要添加keep-alive即可
<keep-alive>
  <component v-bind:is="currentView">
    <!-- 组件在 vm.currentview 变化时改变! -->
  </component>
</keep-alive>

参考:

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

推荐阅读更多精彩内容

  • 此文基于官方文档,里面部分例子有改动,加上了一些自己的理解 什么是组件? 组件(Component)是 Vue.j...
    陆志均阅读 3,794评论 5 14
  • 什么是Vue组件 组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,...
    bacbcc94613b阅读 955评论 0 0
  • Vue/组件 创建组件 单独声明一个Vue.component,使用只需要在Vue实例下使用定义的组件名在组件中d...
    一刀一个小黄鱼阅读 595评论 0 51
  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 5,040评论 0 29
  • 组件 什么是组件? 组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封...
    陆志均阅读 2,418评论 0 0