Vue组件化开发

目录总览:(组件化概念、组件注册、数据存放、组件数据共享、组件插槽、使用步骤)

一、组件化概念

1. 组件化开发思想

组件化思想的特点:标准、分治、复用、组合

2. 组件定义

 **组件化**开发:根据封装的思想,把页面上可重用的 UI 结构封装为组件,从而方便项目的开发和维护。

3. Vue中的组件化开发

 **vue** 是一个**支持组件化开发的前端框架**。

 **vue** 中规定:**组件的后缀名是 .vue**。之前接触到的 App.vue 文件本质上就是一个 vue 的组件,即**单组件**(单文件组件)。

4. Vue组件的三个组成部分

每个 .vue 组件都由 3 部分构成,分别是:

  • template -> 组件的模板结构
  • script -> 组件的 JavaScript 行为
  • style -> 组件的样式

其中,每个组件中必须包含 template 模板结构,而 script 行为style 样式可选的组成部分。

二、组件注册

1. 全局组件🔥

//全局组件使用
<div id="app">
    <组件名称></组件名称>
</div>

//全局组件注册
Vue.component(组件名称, {
    data: 组件数据,
    template: 组件模板内容
})
  • 1.1 全局组件组件可以在app实例内部任意地方使用:我们可以在 app 实例下使用,也可以在 home 实例下使用,也可以在 message 实例下使用。
<body>
  <div id="app">
    <div id="home">
      <span>首页</span>
      <button-counter></button-counter>
    </div>
    <div id="message">
      <span>消息</span>
      <button-counter></button-counter>
    </div>
    <!--调用全局注册组件-->
    <button-counter></button-counter>
  </div>

  <script src="../js/vue.js"></script>
  <script>
     // 2.定义一个组件(全局组件)
     app.component('button-counter',{
       data() {
         return {
           count: 0
         }
       },
       template: `
        <button @click="count++">你点击了{{count}}次</button>`
     })
     // 1.创建Vue的实例对象
     const app = Vue.createApp({
      data(){
        return {
          msg: '你好,Vue3!'
        }
      }
     });
     // 3. 挂载vue实例
     app.mount('#app'); 
  </script>
</body>
  • 1.2 可以设置多个全局组件,代码如下:
<body>
<div id="app">
  <div id="home">
    <span>首页</span>
    <button-counter></button-counter>
  </div>
  <div id="message">
    <span>消息</span>
    <button-counter></button-counter>
    <!--调用第二个注册组件-->
    <lk-box></lk-box>
  </div>
  <!--调用全局注册组件-->
  <button-counter></button-counter>
</div>

<script src="../js/vue.js"></script>
<script>
  // 1.创建Vue的实例对象
  const app = Vue.createApp({
    data(){
      return {
        msg: '你好,Vue3!'
      }
    }
  });

  // 2.定义一个组件(全局组件)
  app.component('button-counter',{
    data() {
      return {
        count: 0
      }
    },
    template: `
        <button @click="count++">你点击了{{count}}次</button>
       `
  })
  // 定义第二个全局组件
  app.component('lk-box',{
    template: `
        <div style="width: 200px;height: 200px;background-color:pink;">
        盒子组件
        </div>
       `
  })

  // 3. 挂载vue实例
  app.mount('#app');
</script>
</body>

  • 1.3 全局组件之间可以相互使用,使用方式如下:我们在定义第二个全局组件,若向使用第一个全局组件,只需要将第一个全局组件的名称标签写入模板template中即可。
// 定义第二个全局组件
app.component('lk-box',{
    template: `
        <div style="width: 200px;height: 200px;background-color:pink;">
        盒子组件
        <button-counter></button-counter>
        </div>
       `
})

2. 局部组件🔥

  • 局部组件只能在注册他的父组件中使用
//局部组件使用
<div id="app">
    <ComponentA></ComponentA>
    <ComponentB></ComponentB>
    <ComponentC></ComponentC>
</div>

//局部组件注册
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
new Vue({
    el: '#app'
    components: {
        'component-a': ComponentA,
        'component-b': ComponentB,
        'component-c': ComponentC,
    }
})

实例:

//局部组件使用
<body>
<div id="app">
  <lk-count></lk-count>
  <cc-count></cc-count>
</div>

<script src="../js/vue.js"></script>
<script>
  // 注册一个局部组件
  const Counter = {
    data() {
      return {
        count: 0
      }
    },
    template: `
        <button @click="count++">你点击了{{count}}次</button>`
  }
  // 注册第二个局部组件
  const Box = {
    template: `
        <div style="width: 200px;height: 200px;background-color:pink;">
        盒子组件
        </div> `
  }
  // 创建Vue的实例对象
  const app = Vue.createApp({
    data(){
      return {
        msg: '你好,Vue3!'
      }
    },
    // 组件选项
    components: {
      'lk-count': Counter,
      'cc-count': Box
    }
  });
  // 挂载vue实例
  app.mount('#app');
</script>
</body>

3. 注意事项

1. data必须是一个函数

2. 组件模板内容必须是单个跟元素

3. 组件模板内容可以是模板字符串(需要浏览器提供ES6语法支持)

4. 组件命名方式

  • 短横线方式:
Vue.component('my-component', { /* ... */ })
  • 驼峰方式:
Vue.component('MyComponent', { /* ... */ })

4.总结

  • 全局组件:在整个Vue实例中都可以被调用,若想要全局组件之间相互使用,只需将想使用全局组件的名称写入 template

  • 局部组件:只能在当前组件中被使用,若想在其他组件中使用,必须使用 components 将其挂载在想使用的组件中,然后再如全局组件那样向模板template写入名称标签

  • 我们之后其实对局部组件用的更多一些。

三、组件数据存放

Data属性的值是一个函数🔥

  • 为什么data在组件中必须是一个函数呢?
    • 当然,如果不是一个函数,Vue直接就会报错。
    • 组件是可复用的vue实例,一个组件被创建好之后,就可能被用在各个地方
    • 而组件不管被复用了多少次,组件中的data数据都应该是相互隔离,互不影响的
    • 基于这一理念,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响
    • 组件中的data写成一个函数数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据
    • 而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果

四、组件之间数据的交互共享

4.1 父组件向子组件传值🔥

1. 组件内部通过props接收传递过来的值

Vue.component(‘menu-item', {
    props: ['title'],
    template: '<div>{{ title }}</div>'
})

2. 父组件通过属性将值传递给子组件

<menu-item title="来自父组件的数据"></menu-item>
<menu-item :title="title"></menu-item>

3. props属性名规则

  • 在props中使用驼峰形式,模板中需要使用短横线的形式
  • 字符串形式的模板中没有这个限制
Vue.component(‘menu-item', {
    // 在 JavaScript 中是驼峰式的
    props: [‘menuTitle'],
    template: '<div>{{ menuTitle }}</div>'
})
<!– 在html中是短横线方式的 -->
<menu-item menu-title=“nihao"></menu-item>

4. props属性值类型

  • 字符串 String
  • 数值 Number
  • 布尔值 Boolean
  • 数组 Array
  • 对象 Object

4.2 子组件向父组件传值🔥

1. 子组件通过自定义事件向父组件传递信息

<button v-on:click='$emit("enlarge-text") '>扩大字体</button>

2. 父组件监听子组件的事件

<menu-item v-on:enlarge-text='fontSize += 0.1'></menu-item>

3. 子组件通过自定义事件向父组件传递信息

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

4. 父组件监听子组件的事件

<menu-item v-on:enlarge-text='fontSize += $event'></menu-item>

4.3 非父子组件间传值🔥

1. 单独的事件中心管理组件间的通信

var eventHub = new Vue()

2. 监听事件与销毁事件

eventHub.$on('add-todo', addTodo)
eventHub.$off('add-todo')

3. 触发事件

eventHub.$emit(‘add-todo', id)

五、组件插槽

5.1 组件插槽的作用

  • 插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签。

  • 父组件向子组件传递内容

5.2 组件插槽基本用法

//插槽的使用
<div id="app">
    <alert-box>有bug发生</alert-box>
    <alert-box>有一个警告</alert-box>
    <alert-box></alert-box>
</div>
//插槽的定义
Vue.component('alert-box', {
      template: `
        <div>
          <strong>ERROR:</strong>
          <slot>默认内容</slot>
        </div>`
});

5.3 具名插槽用法

//具名插槽的使用
<div id="app">
    //第一种:当具名插槽内只有1个标签
    <base-layout>
      <p slot='header'>标题信息</p>
      <p>主要内容1</p>
      <p>主要内容2</p>
      <p slot='footer'>底部信息信息</p>
    </base-layout>
    
    //第二种:当具名插槽内需要填充多个标签
    <base-layout>
      <template slot='header'>
        <p>标题信息1</p>
        <p>标题信息2</p>
      </template>
      <p>主要内容1</p>
      <p>主要内容2</p>
      <template slot='footer'>
        <p>底部信息信息1</p>
        <p>底部信息信息2</p>
      </template>
    </base-layout>
</div>

//具名插槽的定义
Vue.component('base-layout', {
      template: `
        <div>
          <header>
            <slot name='header'></slot>
          </header>
          <main>
            <slot></slot>
          </main>
          <footer>
            <slot name='footer'></slot>
          </footer>
        </div>`
});

5.4 作用域插槽

//作用域插槽的使用
<fruit-list v-bind:list= "list">
    <template slot-scope="slotProps">
        <strong v-if="slotProps.item.current">
            {{ slotProps.item.text }}
        </strong>
    </template>
</fruit-list>

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

推荐阅读更多精彩内容