Vue:学习笔记(六)-组件基础

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chaiyu2002/article/details/83309192

提醒

原帖完整收藏于IT老兵驿站,并会不断更新。

前言

最近在工作中频繁遇到组件,所以就没按照顺序,先总结组件这一章节的内容了,将来再做调整和修改。

(2018-10-24注:这一章粗读了两遍,感觉下面有好些内容都没有理解,有一些难度,看不明白就先修改一会儿,先干点别的。)

正文

基本示例

这是一个例子:

// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

在我看来,组件就是模板、数据,加上对于数据处理的逻辑,这些显示和逻辑,基本是固定的,所以以组件的形式固化出来。(感觉,这话一说出来,立刻就清楚了)

<div id="components-demo">
  <button-counter></button-counter>
</div>
new Vue({ el: '#components-demo' })

id等于“components-demo”是Vue对象的根元素,在它下面创建组件。

组件的复用

这里是将把组件应该理解成类,每一个实例是对象,对象之间是没有关系的。

data 必须是一个函数

只有将data实现为一个函数,才能实现上面的对象之间没有关系的复用。

组件的组织

这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的:

Vue.component('my-component-name', {
  // ... options ...
})

通过 Prop 向子组件传递数据

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

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

感觉这个props仅仅是用来约束,如果没有这个约束,所有在组件的属性中送过来的属性都会被接受。

扫描二维码关注公众号,回复: 4418140 查看本文章

单个根元素

这一章节讲了涉及多个元素的组件是如何组织的。
例如:

<h3>{{ title }}</h3>
<div v-html="content"></div>

如果模板涉及了多个元素,那么需要将这些元素放在一个根元素内,上面这个模板就涉及到两个元素,这个时候需要在外面再包裹一个元素:

<div class="blog-post">
  <h3>{{ title }}</h3>
  <div v-html="content"></div>
</div>

下面的例子涉及到如何设计传递的参数。

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
  v-bind:content="post.content"
  v-bind:publishedAt="post.publishedAt"
  v-bind:comments="post.comments"
</blog-post>

合理的设计应该是:

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:post="post"
></blog-post>
Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <div v-html="post.content"></div>
    </div>
  `
})

通过事件向父级组件发送消息

这段没想明白应该怎么去总结,完全照搬过来没有什么意义。

<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button>

这个是孩子组件(位于父组件之内),可以使用$emit向父组件发送一个自定义的消息。

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

父组件使用v-on去监听这个事件。

使用事件抛出一个值

接着上面的例子,如果想给父组件发送消息的同时,传递参数,需要这样:
孩子组件:

<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>

父组件:

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

这里第二个参数,可以是一个值,或者是一个方法

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

好像不能是对象,这个还要确认一下。

在组件上使用 v-model

有一点含糊了,prop和v-model在这里有什么区别呢?这个部分讲的感觉又有点不清楚。

<input v-model="searchText">

等价于

<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

用在自定义的组件上(上面是标准的HTML元素),则是

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"
></custom-input>

和上面大体接近,只是最后的$event有区别。

为了让它正常工作,这个组件内的 <input> 必须:
将其 value 特性绑定到一个名叫 value 的 prop 上
在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
写成代码之后是这样的:

Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})

现在 v-model 就应该可以在这个组件上完美地工作起来了:
<custom-input v-model="searchText"></custom-input>

意思是:

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"
></custom-input>

这么写和

<custom-input v-model="searchText"></custom-input>

这么写是一个意思,组件里面都要这么写:

Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})

对event进行了一次转发。

通过插槽分发内容

这里讲的是如何把元素的内容传递给组件,叫做分发内容,使用<slot>这样的关键字来接收。

<alert-box>
  Something bad happened.
</alert-box>

上面是一个自定义组件,给这个组件直接传递内容,会得到不正确的结果,需要有能接收这个内容的东西,这个就叫插槽。这个地方感觉讲的不清楚,自己尝试了一下。

如上图,这里并没有显示出内容来,没有用于接收的东西。

改为:

Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box">
      <strong>Error!</strong>
      <slot></slot>
    </div>
  `
})

则:

这样才显示出来。

动态组件

这段又没看懂。

<div id="dynamic-component-demo" class="demo">
  <button v-for="tab in tabs" v-bind:key="tab" class="dynamic-component-demo-tab-button" v-bind:class="{ 'dynamic-component-demo-tab-button-active': tab === currentTab }" 
  v-on:click="currentTab = tab">
    {{ tab }}
  </button>
  <component v-bind:is="currentTabComponent" class="dynamic-component-demo-tab"></component>
</div>
<script>
Vue.component('tab-home', { template: '<div>Home component</div>' })
Vue.component('tab-posts', { template: '<div>Posts component</div>' })
Vue.component('tab-archive', { template: '<div>Archive component</div>' })
new Vue({
  el: '#dynamic-component-demo',
  data: {
    currentTab: 'Home',
    tabs: ['Home', 'Posts', 'Archive']
  },
  computed: {
    currentTabComponent: function () {
      return 'tab-' + this.currentTab.toLowerCase()
    }
  }
})
</script>
<style>
.dynamic-component-demo-tab-button {
  padding: 6px 10px;
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
  border: 1px solid #ccc;
  cursor: pointer;
  background: #f0f0f0;
  margin-bottom: -1px;
  margin-right: -1px;
}
.dynamic-component-demo-tab-button:hover {
  background: #e0e0e0;
}
.dynamic-component-demo-tab-button-active {
  background: #e0e0e0;
}
.dynamic-component-demo-tab {
  border: 1px solid #ccc;
  padding: 10px;
}
</style>

解析 DOM 模板时的注意事项

这段和上面那段有关联,但是好像也是没写清楚,继续等待深度理解。

总结

断断续续,花了三天,终于大体看明白了(花了很多时间看这个slot,也把后面的关于slot的看了一遍,基本梳理清楚),感觉这一章节是Vue的核心内容,还需要不断完善这篇笔记。

参考

https://cn.vuejs.org/v2/guide/components.html

猜你喜欢

转载自blog.csdn.net/chaiyu2002/article/details/83309192