初识vue(7)——组件化

组件化的意义

什么是组件化:将一个大问题拆解为一个一个小问题,去解决一个一个的小问题,当解决完所有小问题,那么大问题也就解决了。
在这里插入图片描述
比如这个页面,可以先将这个大页面分为2部分,上部分导航栏,下部分显示内容。页面上部分的导航栏,有6个功能不同的按钮,可以看成6个组件,6个组件组成导航栏,然后导航栏和下部分组成整个页面。这里的组件都是可以复用。

组件化优势:
1.高内聚低耦合,拆分项目,团队分工,加快进展;
2.组件可复用,方便维护,方便阅读;

组件的基本使用

组件的使用主要是3步:
1.创建组件构造器:Vue.extend。
2.注册组件:Vue.component。
3.使用组件。

这是组件最原始的写法,看着比较繁琐:

<body>

<div id="app">
  <!--3.使用组件-->
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <div>
    <div>
      <my-cpn></my-cpn>
    </div>
  </div>
</div>
<my-cpn></my-cpn>
<script>
  // 1.创建组件构造器对象
  const cpnC = Vue.extend({
    template: `
      <div>
        <h2>你好</h2>
        <p>今天天气很好</p>
      </div>`
  })

  // 2.注册组件
  Vue.component('my-cpn', cpnC)

  const app = new Vue({
    el: '#app',
    data: {
      message: 'hi'
    }
  })
</script>

</body>

组件分2种:

全局组件(全局可以用)和局部组件(只能在实例的vue里面用,这里只能在app块里面使用,app2块里面无法使用):

<body>

<div id="app">
  <cpn></cpn>
  <cpn></cpn>
  <cpn></cpn>
</div>

<div id="app2">
  <cpn></cpn>
</div>
<script>
  // 1.创建组件构造器
  const cpnC = Vue.extend({
    template: `
      <div>
        <h2>你好</h2>
        <p>今天天气不错</p>
      </div>
    `
  })

  // 2.注册组件(全局组件, 意味着可以在多个Vue的实例下面使用)
  // Vue.component('cpn', cpnC)

  const app = new Vue({
    el: '#app',
    data: {
      message: 'hi'
    },
    components: {
      // cpn使用组件时的标签名
      cpn: cpnC
    }
  })

  const app2 = new Vue({
    el: '#app2'
  })
</script>

</body>

语法糖形式写法:

<body>

<div id="app">
  <cpn1></cpn1>
  <cpn2></cpn2>
</div>
<script>
  // 1.全局组件注册的语法糖
  // 1.创建组件构造器
  // const cpn1 = Vue.extend()

  // 2.注册组件
  Vue.component('cpn1', {
    template: `
      <div>
        <h2>你好</h2>
        <p>今天天气不错</p>
      </div>
    `
  })

  // 2.注册局部组件的语法糖
  const app = new Vue({
    el: '#app',
    data: {
      message: 'hi'
    },
    components: {
      'cpn2': {
        template: `
          <div>
            <h2>你好2</h2>
            <p>今天天气不错</p>
          </div>
    `
      }
    }
  })
</script>
</body>

父子组件

可以理解为与继承相反的,大的包含小的叫父,小的叫子,这里cpnC1是子,cpnC2叫父:

<body>

<div id="app">
  <cpn2></cpn2>
  <!--<cpn1></cpn1>-->
</div>

<script src="../js/vue.js"></script>
<script>
  // 1.创建第一个组件构造器(子组件)
  const cpnC1 = Vue.extend({
    template: `
      <div>
            <h2>你好</h2>
            <p>今天天气不错</p>
      </div>
    `
  })


  // 2.创建第二个组件构造器(父组件)
  const cpnC2 = Vue.extend({
    template: `
      <div>
        <h2>你好2</h2>
        <p>今天天气不错</p>
        <cpn1></cpn1>
      </div>
    `,
    components: {
      cpn1: cpnC1
    }
  })

  // root组件
  const app = new Vue({
    el: '#app',
    data: {
      message: 'hi'
    },
    components: {
      cpn2: cpnC2
    }
  })
</script>

</body>

剥离组件代码

模块代码和js写在一起,看着很混乱,所以这里将模板剥离开来写,这里可以用script type=“text/x-template” id="“标签和template id=”"(id在注册的时候会用到)标签来写,常用第二种。

<body>

<div id="app">
  <cpn></cpn>
  <cpn></cpn>
  <cpn></cpn>
</div>

<!--1.script标签, 注意:类型必须是text/x-template-->
<!--<script type="text/x-template" id="cpn">-->
<!--<div>-->
  <!--<h2>你好</h2>-->
  <!--<p>今天天气不错</p>-->
<!--</div>-->
<!--</script>-->

<!--2.template标签-->
<template id="cpn">
  <div>
    <h2>你好</h2>
    <p>今天天气不错</p>
  </div>
</template>

<script src="../js/vue.js"></script>
<script>

  // 1.注册一个全局组件
  Vue.component('cpn', {
    template: '#cpn'
  })

  const app = new Vue({
    el: '#app',
    data: {
      message: 'hi'
    }
  })
</script>

</body>

组件数据

这里关于组件模块数据存放有几个注意:
1.不能直接从实例Vue(也就是app的data)里面取数据。
2.要从实例Vue或者其他模块里面取数据,涉及到父子组件通信问题,后面讲。
3.只能直接取用自己模块里面的data数据。
4.模块自己的data不是一个对象,而是一个有返回值的函数。
5.rops中的驼峰标识,在html中会报错,用-小写代替大写的写法,代替驼峰标识。my-cpn(myCpn)

<body>

<div id="app">
  <cpn></cpn>
  <cpn></cpn>
  <cpn></cpn>
</div>
<template id="cpn">
  <div>
    <h2>{{title}}</h2>
    <p>今天天气不错</p>
  </div>
</template>

<script>

  Vue.component('cpn', {
    template: '#cpn',
    data() {
      return {
        title: 'abc'
      }
    }
  })

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好',
      // title: '标题'
    }
  })
</script>

</body>

为什么模块里面的数据一定要是一个函数,而不是对象?
组件是可复用的vue实例,一个组件被创建好之后,就可能被用在各个地方,而组件不管被复用了多少次,组件中的data数据都应该是相互隔离,互不影响的,每次使用,都应该是新的数据,基于这一理念,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响,这正好是函数的特性。

组件通信父传子

在子组件中定义属性props存放就收来的信息,再用v-bind去接收父组件的消息放在定义好的props里面。

<body>
<div id="app">
  <!--<cpn v-bind:cmovies="movies"></cpn>-->
  <!--<cpn cmovies="movies" cmessage="message"></cpn>-->

  <cpn :cmessage="message" :cmovies="movies"></cpn>
</div>

<template id="cpn">
  <div>
    <ul>
      <li v-for="item in cmovies">{{item}}</li>
    </ul>
    <h2>{{cmessage}}</h2>
  </div>
</template>

<script>
  // 父传子: props
  const cpn = {
    template: '#cpn',
    // props: ['cmovies', 'cmessage'],
    props: {
      // 1.类型限制
      // cmovies: Array,
      // cmessage: String,

      // 2.提供一些默认值, 以及必传值
      cmessage: {
        type: String,
        default: 'abcd',
        required: true
      },
      // 类型是对象或者数组时, 默认值必须是一个函数
      cmovies: {
        type: Array,
        default() {
          return []
        }
      }
    },
    data() {
      return {}
    },
    methods: {

    }
  }

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      movies: ['海贼王', '火影', '死神']
    },
    components: {
      cpn
    }
  })
</script>

组件通信子传父

子发射事件,并携带信息传给父组件,父组件用V-on去响应子组件的发射事件,并接收信息。

<body>
<div id="app">
    <cpn @item-click="Total"></cpn>
    <h1>点击总次数:{{total}}</h1>
</div>
</body>
<template id="cpnC">
    <div>
        <button @click="btnClickAdd">+</button>
        <button @click="btnClickSup">-</button>
        <h1>按钮显示数:{{showCount}}</h1>
    </div>
</template>
<script>
    const cpn = {
        template:'#cpnC',
        data(){
            return{
                count:0,
                showCount:0,
            }
        },
        methods:{
            btnClickAdd(){
                // 发射事件: 自定义事件
                this.count++;
                this.showCount++;
                console.log(this.count);
                this.$emit('item-click', this.count)
            },
            btnClickSup(){
                // 发射事件: 自定义事件
                this.count++;
                this.showCount--;
                console.log(this.count);
                this.$emit('item-click', this.count)
            }
        }
    }
    Vue.component('cpn',cpn)
    const app = new Vue({
        el:'#app',
        data:{
            message:"你好",
            total:0,
        },
        methods: {
            Total(total){
                this.total = total;
            }
        }
    })
</script>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值