Vue组件化开发(一)

6 篇文章 0 订阅

1.认识组件化

我们将一个完整的页面分成很多个组件。每个组件都用于实现页面的一个功能块。而每一个组件又可以进行细分。
在这里插入图片描述
组件化思想的应用:

  • 有了组件化的思想,我们尽可能的将页面拆分成一个个小的、可复用的组件。
  • 这样让我们的代码更加方便组织和管理,并且扩展性也更强。

2.注册组件的基本步骤

组件的使用分成三个步骤:

创建组件构造器

调用Vue.extend()方法

  // 1.创建组件构造器对象
  const cpnC = Vue.extend({
    template: `
      <div>
        <h2>我是标题</h2>
        <p>我是内容, 哈哈哈哈</p>
        <p>我是内容, 呵呵呵呵</p>
      </div>`
  })

调用Vue.extend()创建的是一个组件构造器。
通常在创建组件构造器时,传入template代表我们自定义组件的模板。
该模板就是在使用到组件的地方,要显示的HTML代码。

注册组件

调用Vue.component()方法

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

调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。
所以需要传递两个参数:1、注册组件的标签名 2、组件构造器

使用组件

在Vue实例的作用范围内使用组件
在这里插入图片描述

3.全局组件和局部组件

  • 当我们通过调用Vue.component()注册组件时,组件的注册是全局的
    这意味着该组件可以在任意Vue示例下使用。
<div id="app">
  <cpn></cpn>
</div>
<div id="app2">
  <cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<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',
  })
  const app2 = new Vue({
    el: '#app2',
  })

在这里插入图片描述

  • 如果我们注册的组件是挂载在某个实例中, 那么就是一个局部组件
<div id="app">
  <cpn></cpn>
</div>

<div id="app2">
  <cpn></cpn>
</div>
  // 1.创建组件构造器
  const cpnC = Vue.extend({
    template: `
      <div>
        <h2>我是标题</h2>
        <p>我是内容,哈哈哈哈啊</p>
      </div>
    `
  })
  const app = new Vue({
    el: '#app',
  })
  const app2 = new Vue({
    el: '#app2',
    components: {
        // cpn使用组件时的标签名,用components实现局部组件
        cpn: cpnC
    }
  })

在这里插入图片描述

4.父组件和子组件

在前面我们看到了组件树:

  • 组件和组件之间存在层级关系
  • 而其中一种非常重要的关系就是父子组件的关系
    我自己理解的构建过程,之前听课听得迷迷糊糊的这样一看清晰了一点,首先要牢记组件的构建过程
    在这里插入图片描述

5.注册组件语法糖

在上面注册组件的方式,可能会有些繁琐。

  • Vue为了简化这个过程,提供了注册的语法糖。
  • 主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替。
  • 就是 Vue.component(‘cpn’, cpnC)我们把cpnC用一个对象代替了,对象里是template模块

1.全局组件注册的语法糖

  Vue.component('cpn1', {
    template: `
      <div>
        <h2>我是标题1</h2>
        <p>我是内容, 哈哈哈哈</p>
      </div>
    `
  })

2.注册局部组件的语法糖

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    },
    components: {
      'cpn2': {
        template: `
          <div>
            <h2>我是标题2</h2>
            <p>我是内容, 呵呵呵</p>
          </div>
    `
      }
    }
  })

6.模板的分离写法

还有一个地方的写法比较麻烦,就是template模块写法。如果我们能将其中的HTML分离出来写,然后挂载到对应的组件上,必然结构会变得非常清晰。
Vue提供了两种方案来定义HTML模块内容:

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

使用<script>标签,注意:类型必须是text/x-template

<script type="text/x-template" id="cpn">
	<div>
		<h2>我是标题</h2>
		<p>我是内容,哈哈哈</p>
	</div>
</script>

使用<template>标签

<template id="cpn">
  <div>
    <h2>我是标题</h2>
    <p>我是内容,呵呵呵</p>
  </div>
</template>

7.组件数据存放

组件可以访问Vue实例数据吗?

组件不能直接访问Vue实例中的data数据
在这里插入图片描述

为什么是一个函数呢?

为什么data在组件中必须是一个函数呢?

  • 首先,如果不是一个函数,Vue直接就会报错。
  • 其次,原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
    我们先看一下下面这两个案例
 function abc() {
    return {
      name: 'smy',
      age: 18
    }
  }
  let obj1 = abc()
  let obj2 = abc()
  let obj3 = abc()
  //判断是不是一个对象,我改变obj1其他两个不变,不是同一个对象
  obj1.name = 'kobe'
  console.log(obj2);
  console.log(obj3);

在这里插入图片描述

我们每次用的都是obj这一个对象,这里就会遇到问题了,我改obj1的值2,3,也跟着变了

  const obj = {
    name: 'smy',
    age: 18
  }

  function abc() {
    return obj
  }

  let obj1 = abc()
  let obj2 = abc()
  let obj3 = abc()
  
  obj1.name = 'kobe'
  console.log(obj2);
  console.log(obj3);

在这里插入图片描述
回到组件中

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

<template id="cpn">
  <div>
    <h2>当前计数: {{counter}}</h2>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
  </div>
</template>
  Vue.component('cpn', {
    template: '#cpn',
    data() {
      return {
        counter: 0
      }
    },
    methods: {
      increment() {
        this.counter++
      },
      decrement() {
        this.counter--
      }
    }
  })

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    }
  })

我们以函数的形式写,各组件之间是相互不会产生影响的
在这里插入图片描述
若修改为下面的这种,修改一个其他组件也会跟着改变

 const obj = {
    counter: 0
  }
  Vue.component('cpn', {
    template: '#cpn',
    data() {
      return obj
    },
  })

在这里插入图片描述

8.父级向子级传递

props基本用法

在组件中,使用选项props来声明需要从父级接收到的数据。
props的值有两种方式:

方式一:字符串数组,数组中的字符串就是传递时的名称。

接下来我们进一步分析
1.看上面父子组件的部分,root组件和父组件之间也是父子组件的关系,root组件是父组件,我们现根据这个关系建个父子组件,下面这个引用是不成立的子组件不能引用父组件中的数据
在这里插入图片描述
那我们就要想,我父组件怎么把这个数据给子组件传过去呢?
我们用props(属性),给上面的代码中添加如下代码

const cpn = {
    template: '#cpn',
    props: ['cmovies'],
    data() {
        return {}
    },
    methods: {}
  }

用在这里就可以用父组件中的movies数组了,一定要写v-bind不写的话直接赋值的是一个‘movies’字符串,不会去寻找变量movies对cmovies进行赋值

<div id="app">
  <cpn :cmovies="movies"></cpn>
</div>

数组形式完整代码如下

<div id="app">
    <cpn :cmovies="movies"></cpn>
</div>
<template id="cpn">
    <div>
        <ul>
            <li v-for="item in cmovies">{{item}}</li>
        </ul>
    </div>
</template>

<script src="../js/vue.js"></script>
<script>
    // 父传子: props
    const cpn = {
        template: '#cpn',
        props: ['cmovies'],
        data() {
            return {}
        },
        methods: {}
    }

    const app = new Vue({
        el: '#app',
        data: {
            message: '你好啊',
            movies: ['海王', '海贼王', '海尔兄弟']
        },
        components: {
            cpn
        }
    })
</script>
方式二:对象,对象可以设置传递时的类型,也可以设置默认值等
<div id="app">
  <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 src="../js/vue.js"></script>
<script>
  const cpn = {
    template: '#cpn',
    props: {
      cmessage: {
        type: String,// 1.类型限制cmovies: Array,
        default: 'aaaaaaaa',// 2.提供一些默认值
        required: true //3.必传值
      },
      // 类型是obj对象或者array数组时, 默认值必须是一个函数
      cmovies: {
        type: Array,
        default() {
          return []//类型是对象或者数组时要写一个return
        }
      }
    },
    data() {
      return {}
    },
    methods: {}
  }
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      movies: ['海王', '海贼王', '海尔兄弟']
    },
    components: {
      cpn
    }
  })

props数据验证

  • 在前面,我们的props选项是使用一个数组。
  • 我们说过,除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了。
  • 验证都支持哪些数据类型呢?
    String Number Boolean
    Array Object Date
    Function Symbol
  • 当我们有自定义构造函数时,验证也支持自定义的类型
    在这里插入图片描述

props驼峰标识

比如childMyMessage在赋值时,大写要变小写并在前面加一个杠‘-’

<div id="app">
  <cpn :c-info="info" :child-my-message="message" v-bind:class></cpn>
</div>

<template id="cpn">
  <div>
    <h2>{{cInfo}}</h2>
    <h2>{{childMyMessage}}</h2>
  </div>
</template>
  const cpn = {
    template: '#cpn',
    props: {
      cInfo: {//注意这种有驼峰的要用-分割
        type: Object,
        default() {
          return {}
        }
      },
      childMyMessage: {
        type: String,
        default: ''
      }
    }
  }

  const app = new Vue({
    el: '#app',
    data: {
      info: {
        name: 'smy',
        age: 18,
        height: 1.88
      },
      message: 'aaaaaa'
    },
    components: {
      cpn
    }
  })

9.子级向父级传递

props用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中。我们应该如何处理呢?
这个时候,我们需要使用自定义事件来完成。

  • 当子组件需要向父组件传递数据时,就要用到自定义事件了。
  • 我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。

自定义事件的流程:

  • 在子组件中,通过==$emit()==来触发事件。
  • 在父组件中,通过v-on来监听子组件事件。

我们来看一个简单的例子:
左侧导航栏是一个子组件,我们点击导航栏时,右侧的父组件中要接收一下导航栏传过去的信息,做出相应的变化
在这里插入图片描述
在这里插入图片描述
代码如下

<div id="app">
  <cpn @item-click="cpnClick"></cpn>
</div>

<template id="cpn">
  <div>
    <button v-for="item in categories"
            @click="btnClick(item)">
      {{item.name}}
    </button>
  </div>
</template>

<script src="../js/vue.js"></script>
<script>
  const cpn = {
    template: '#cpn',
    data() {
      return {
        categories: [
          {id: 'aaa', name: '热门推荐'},
          {id: 'bbb', name: '手机数码'},
          {id: 'ccc', name: '家用家电'},
          {id: 'ddd', name: '电脑办公'},
        ]
      }
    },
    methods: {
      btnClick(item) {
        this.$emit('item-click', item)
      }
    }
  }
  const app = new Vue({
    el: '#app',
    data: {},
    components: {
      cpn
    },
    methods: {
      cpnClick(item) {
        console.log('cpnClick', item);
      }
    }
  })
</script>

根据上面的编写顺序图,我们还可以写一个按钮点击
想子组件把counter值传给父组件
在这里插入图片描述

<div id="app">
    <cpn @increment="clickcounter" @decrement="clickcounter"></cpn>
    <h2>当前计数: {{total}}</h2>
</div>

<template id="cpn">
    <div>
        <button @click="add">+</button>
        <button @click="del">-</button>
    </div>
</template>
//子组件
const cpn = {
        template:'#cpn',
        data(){
            return{
                counter:0
            }
        },
        methods: {
            add(){
                this.counter++;
                this.$emit('increment',this.counter)
            },
            del(){
                this.counter--;
                this.$emit('decrement',this.counter)
            }
        }
    }
//父组件
    const app = new Vue({
        el: '#app',
        data: {
            total:0
        },
        methods:{
            clickcounter(counter){
                this.total=counter;
            }
        },
        components:{
            cpn
        }
    })

我们还可以把父子组件写到一起
在这里插入图片描述
(以上内容根据微博“coderwhy”的vue视频课程整理,感谢王红元老师ღ( ´・ᴗ・` )比心)

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值