浅谈Vue组件

1. 什么是组件

image.png

组件化就是把页面拆分成一块块的,后期维护很简单
组件其实也是vue的实例,组件是可以反复使用的vue实例

  • 全局注册组件
    就是把组件用Vue.component()注册
<body>
  <div id="app">
    <!-- 3、使用组件 -->
    <my-header></my-header>
  </div>
</body>
<script src="vue.js"></script>
<script>
  // 全局注册组件

  // 1、定义组件
  const MyHeader = { 
    template: `<header>头部</header>`, 
  }

  // 2、全局注册组件
  Vue.component('my-header', MyHeader)

  new Vue({
    el: '#app'
  })
</script>
  • 局部注册组件
    就是把组件注册在某个Vue实例中,用components:{}注册
<body>
  <div id="app">
    <!-- 3、使用组件 -->
    <my-header></my-header>
  </div>
</body>
<script src="vue.js"></script>
<script>
  // 局部注册组件
  // 1、定义组件
  const MyHeader = { 
    template: `<header>头部</header>`, 
  }
  new Vue({
    el: '#app',
    // 2、局部注册组件
    components: {
      'my-header': MyHeader
    }
  })
</script>

2. 组件间的传值

1. 父组件给子组件传值
  • 父组件在调用子组件的地方需要添加一个属性<my-content test = "测试"/>
  • 属性的值”测试”就是你要传递给子组件的值
  • 在子组件定义的地方添加一个选项叫props:{}
  • 在props里放父组件传递的属性名,也就是test就可以了,要注意的是,如果父组件传递给子组件的值是变量,Number或者布尔值就需要v-bind了!props内存放值有两种方式
  • 第一种:数组:props:[‘test’],之后就可以在子组件中使用了
  • 第二种:对象:props:{test:String},这是写法一用来验证传递数据的有效性,因为父子组件可能不是一个人写的,如果数据类型不对,就会警告,可以及时调整。
  • Props:{test:{type:String,default:’默认值’}}这是第二种写法,既要验证数据类型也要设置默认值,如果默认值是对象或者函数,则默认值需要时一个有返回值的函数function () {return {}}
<body>
  <div id="app">
    <!-- <my-content test = "测试" :count="100" :flag="true" :tip="tip"/> -->
    <my-content :count="100" :flag="true" :tip="tip"/>
  </div>
</body>
<template id="content">
  <div>
    我这里是内容区域 --- {{ test }} -- {{ count }} --- {{ flag }} --- {{ tip }}
  </div>
</template>
<script src="vue.js"></script>
<script>
  // 组件的名称不能和模板的id同名
  const Content = {
    template: '#content',
    // props: ['test', 'count', 'flag', 'tip']
    // props: {
    //   test: String,
    //   count: Number,
    //   flag: Boolean,
    //   tip: String
    // }
    props: {
      test: {
        type: String,
        default: '测试数据了' // 如果父组件有这个属性,那么就用父组件的值,没有这个属性,直接使用这个值
      }
    }
  }
  new Vue({
    el: '#app',
    data: {
      tip: '提示'
    },
    components: {
      'my-content': Content
    }
  })
</script>
2. 子组件给父组件传值
  • 子组件给父组件传值时,需要在父组件调用子组件的地方,给它绑定一个自定义事件,事件后面不要加(),例:<my-content @myevent="getData"/>
  • 在父组件选项methods中使用这个getData(val){},其中参数val是默认传递的,传递的就是子组件传递给父组件的值
  • 而在子组件如何传递呢?如下!
  • 在子组件种。你可以通过生命周期的钩子函数,也可以是组件自己的事件去触发父组件中的自定义事件myevent,使用固定语法emit来传递例:this.$emit('myevent', 10000),这样就把名字为myevent的参数名,参数为10000的整个值广播出去了,父组件只要接受myevent就可以了!
<body>
  <div id="app">
    <my-content @myevent="getData"/>
  </div>
</body>
<template id="content">
  <div>
    我这里是内容区域
  </div>
</template>
<script src="vue.js"></script>
<script>
  /**
   * 父组件调用子组件的地方,给他绑定一个自定义的事件, 事件不要加()
   *      <my-content @myevent="getData"/>
   * 在父组件选项methods中实现此事件,默认参数为你将从子组件得到的值
   *    methods: {
          getData (val) { // val为从子组件中获取到的值
            console.log(val)
          }
        },
      
      在子组件中,可以是生命周期钩子函数,也可以是组件自己的事件 去 触发 父组件中的自定义事件
          this.$emit('myevent', 10000)
   **/
  const Content = {
    template: '#content',
    mounted () {
      this.$emit('myevent', 10000)
    }
  }

  new Vue({
    el: '#app',
    data: {},
    methods: {
      getData (val) { // val为从子组件中获取到的值
        console.log(val)
      }
    },
    components: {
      'my-content': Content
    }
  })
</script>
3. 非父子组件间传值
  • 中央事件总线传值const bus = new Vue()他就类似于一个快递员的身份,需要确保数据有人接受的情况下,就可以接受参数然后传递参数给需要的人!
  • 第一步:给需要这个参数的组件,定义bus.$on(‘参数名’,(val)={对收到的val做手脚}),一般写在钩子函数mounted中。还要注意这里尽量使用箭头函数避免this指向出现问题
  • 第二步:在确定了有接受的组件时,就可以给要发送的组件设置了!在发送参数的组建中的methods中添加一个自定义函数,在里面定义bus.emit(‘参数名’,参数),当触发了bus.emit时,像外广播了一个参数名,然后另一个组件通过bus.$on接收到了参数名相同的参数值,这样就形成了非父子组件之间的值传递
<body>
  <div id="app">
    <my-list></my-list>
    <my-count></my-count>
  </div>
</body>
<template id="list">
  <ul>
    <li>111<button @click="add">+1</button></li>
    <li>222<button @click="add">+1</button></li>
    <li>333<button @click="add">+1</button></li>
    <li>444<button @click="add">+1</button></li>
    <li>555<button @click="add">+1</button></li>
  </ul>
</template>
<template id="count">
  <div>
    总量是:{{ num }}
  </div>
</template>
<script src="vue.js"></script>
<script>
  /**
   *  非父子组件传值 ---- 兄弟组件传值                   (邮差与信的故事)
   *  ------------------ 中央事件总线传值  1. const bus = new Vue()
   * 
   *  先要确保 收信 的那个人是存在的
   *  然后写信的人 写信 给邮差
   *  邮差给送
   * 
   *  // 此处一定要注意this指向,可以使用 => 
   *  2.在接收端通过 bus.$on('收信信号', function (val) {
   * 
   *  })
   * 
   *  3.在发送端通过 bus.$emit('收信信号', val)
   * */
const bus = new Vue()

const List = {
  template: '#list',
  methods: {
    add () {
      bus.$emit('count-event', 1)
    }
  }
}
const Count = {
  template: '#count',
  data () {
    return {
      num: 0
    }
  },
  mounted () { // 一般情况下接收都使用 生命周期钩子函数
    bus.$on('count-event', (val) => { // 此处一定要注意this指向,可以使用 =>
      console.log(val)
      this.num += val
    })
  }
}
new Vue({
  el: '#app',
  components: {
    'my-list': List,
    'my-count': Count
  }
})
</script>
4. 动态组件

<component is="组件名称"></component>

概述:让当前画面在几个组件中来回切换,类似你的手机屏幕,同一个屏幕可以打开不同的app显示不同的内容。

使用:一般在页面只写一个类似于<component :is="tem"></component>的组件,页面有按钮操控tem在data中的值,一旦改变值,在components中注册名称为改变得值得组件,就可以在页面中显示出所对应的组件了。

但是随之的问题就出现了,每次切换回前一个组件时,上次的操作就会被清除,所以需要用keep-alive把components包裹起来

keep-alive:保留组件的状态,避免组件的重新渲染 --- 类似于手机软件使用中按了home键之后应用程序的状态
但是有些时候就是需要切换回页面数据清除,所以只需要给keep-alive添加一个include属性就可以了,后面的属性值是在组件注册时定义的名称name的值。添加上的组件就会保存之前的信息,而没有添加的组件name就会数据消失

动态组件生命周期钩子函数

每个组件都会有两个钩子函数activated()---正在用的,deactivated()---后台的,如果该组件在keep-alive的include内,那么该组件再被切换时,会触发deactivated()钩子函数类似于后台运行,在使用时会触发activated()钩子函数

<body>
  <div id="app">
    <button @click="tem='my-a'">AAA</button>
    <button @click="tem='my-b'">BBB</button>
    <button @click="tem='my-c'">CCC</button>
    <keep-alive include="a,b">
      <component :is="tem"></component>
    </keep-alive>
    
  </div>
</body>
<template id="acom">
  <div>
    <input type="text" placeholder="a组件">
  </div>
</template>
<template id="bcom">
  <div>
    <input type="text" placeholder="b组件">
  </div>
</template>
<template id="ccom">
  <div>
    <input type="text" placeholder="c组件">
  </div>
</template>
<script src="vue.js"></script>
<script>
  /**
   * keep-alive 
   *  保留组件的状态,避免组件的重新渲染  ---  类似于手机软件使用中按了home键之后应用程序的状态
   *  添加include 可以 只给部分组件保留状态,需要定义组件时添加name属性
   * 
   * 每个组件都会有 两个生命周期钩子函数
   *    activated()     正在用的
   *    deactivated()   后台的
   * */
const Acom = {
  name: 'a',
  template: '#acom',
  activated () {
    console.log(' a 正在被使用')
  },
  deactivated () {
    console.log(' a 被雪藏了')
  }
}
const Bcom = {
  name: 'b',
  template: '#bcom',
  activated () {
    console.log(' b 正在被使用')
  },
  deactivated () {
    console.log(' b 被雪藏了')
  }
}
const Ccom = {
  template: '#ccom',
  activated () {
    console.log(' c 正在被使用')
  },
  deactivated () {
    console.log(' c 被雪藏了')
  }
}

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

推荐阅读更多精彩内容

  • 组件(Component)是Vue.js最核心的功能,也是整个架构设计最精彩的地方,当然也是最难掌握的。...
    六个周阅读 5,580评论 0 32
  • Vue 实例 属性和方法 每个 Vue 实例都会代理其 data 对象里所有的属性:var data = { a:...
    云之外阅读 2,198评论 0 6
  • 40、React 什么是React?React 是一个用于构建用户界面的框架(采用的是MVC模式):集中处理VIE...
    萌妹撒阅读 1,001评论 0 1
  • 一、了解Vue.js 1.1.1 Vue.js是什么? 简单小巧、渐进式、功能强大的技术栈 1.1.2 为什么学习...
    蔡华鹏阅读 3,311评论 0 3
  • 前言 开发一个React应用,更多的是在编写组件,而React组件最小的单位就是React元素,编写组件的最大的好...
    itclanCoder阅读 1,140评论 0 1