一文搞懂组件 Vue component (上篇)

前言

  vue作为前端目前三大主流框架之一,在前端中也是占有重要的地位。特别是在国内,现在想要找一份前端的工作,那么学会vue,将你的不二之选

  vue目前为什么这么重要呢?因为vue的作者是中国人。那当然不是啦~ 最最最最重要的原因是它有很多优点:

  1. 双向数据绑定
  2. 组件化
  3. 单页面应用用户体验好
  4. 简单易学
  5. ……

  好了,现在知到vue.js的优点就是简单易学,那接下来我们就一起来学习学习它的组件化开发 --> component

什么是组件

  我们来看看官网的介绍,他说是可复用的 Vue 实例。那怎么复用呢?复用什么呢?之前我们写过了css样式,当有些样式是一样的,我们就会将它写到一个文件里然后通过@import url("CSS文件路径");将css文件引入,这样就可以不用多写重复的样式了。

  那么组件你可以理解成html、css、javaScript的集合,然后在其他地方引用。之前引入的css或者引入js都是纯粹的它的样式或者行为。而组件包过HTML代码、css代码、js代码,也就是说一个组件就有自己的结构样式行为了。有了组件,我们的代码的重复率就不会那么高了,代码的复用性就增强了。因为有很多页面的其中一部分都是一样的,比如:tabbar、导航栏等等。

学习组件

1. 组件的基本使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件化基本使用</title>
</head>
<body>
    <div id="app">
        <h1>This is a piece of app message!</h1>
        <!-- 3.使用组件 -->
        <test-cpn></test-cpn>
    </div>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
        //1.创建组件构造器对象
        const TestCpn = Vue.extend({
            // template --> 定义组件的HTML模板
            template: `
            <div>
                <h2>组件标题</h2>
                <p>组件内容</p>
            </div>
            `
        })
        //2.注册组件
        // Vue.component('组件的标题','构造器对象')
        Vue.component('test-cpn', TestCpn);
        const vm = new Vue({
            el: '#app'
        })
    </script>
</body>
</html>

组件的基本使用就是这三个步骤:

  1. 创建组件构造器对象
  2. 注册组件
  3. 使用组件

在这里插入图片描述

  当然组件可以使用多次,就像这样,你使用一次,它就渲染一次,它使用多少次,他就渲染多少次。你是不是开始觉得组件有点东西了!

<div id="app">
    <h1>This is a piece of app message!</h1>
    <!-- 3.使用组件 -->
    <test-cpn></test-cpn>
    <test-cpn></test-cpn>
    
    <!-- 使用单标签 -->
    <test-cpn/>
</div>

在这里插入图片描述

  组件中还可以定义data,但值得注意的是组件的data必须是一个函数且data函数要返回一个对象

<script>
    //1.创建组件构造器对象
    const TestCpn = Vue.extend({
        // template --> 定义组件的HTML模板
        template: `
        <div>
            <h2>组件标题</h2>
            <p>组件内容</p>
            {{mes}}
        </div>
        `,
        // data --> 用于存放组件的数据
        data() {
            return {
                mes: 'hello vue component!'
            }
        }
    })
    //2.注册组件
    // Vue.component('组件的标题','构造器对象')
    Vue.component('test-cpn', TestCpn);
    const vm = new Vue({
        el: '#app'
    })
</script>

在这里插入图片描述

  那么有人就有疑惑了!现在组件不是只有结构吗?样式呢?行为呢?好的!show code!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件化基本使用</title>
    <style>
        .some-style{
            color: red;
            font-size: 20px;
            font-weight: bolder;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>This is a piece of app message!</h1>
        <!-- 3.使用组件 -->
        <test-cpn></test-cpn>
        <test-cpn></test-cpn>

        <!-- 使用单标签 -->
        <test-cpn/>
    </div>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
        //1.创建组件构造器对象
        const TestCpn = Vue.extend({
            // template --> 定义组件的HTML模板
            template: `
            <div>
                <h2>组件标题</h2>
                <p class="some-style">组件内容</p>
                {{mes}}
                <button @click="handleBtn">点我你就知道了</button>
            </div>
            `,
            // data --> 用于存放组件的数据
            data() {
                return {
                    mes: 'hello vue component!'
                }
            },
            // methods --> 组件的方法都写到这里面
            methods: {
                handleBtn() {
                    console.log('这不就是组件的行为了吗?讨厌!')
                }
            }
        })
        //2.注册组件
        // Vue.component('组件的标题','构造器对象')
        Vue.component('test-cpn', TestCpn);
        const vm = new Vue({
            el: '#app'
        })
    </script>
</body>
</html>

在这里插入图片描述

  好了,现在我们知道组件用也有data、也有methods。其实组件还有computed、watch、等等。

  其实我们通过 Vue.component() 注册的组件都是全局组件,这也就意味着可以在多个Vue的实例中使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件化基本使用</title>
    <style>
        .some-style{
            color: red;
            font-size: 20px;
            font-weight: bolder;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>This is a piece of app message!</h1>
        <!-- 3.使用组件 -->
        <test-cpn></test-cpn>
        <test-cpn></test-cpn>

        <!-- 使用单标签 -->
        <test-cpn/>
    </div>

    <div id="app2">
        <hr>
        <h1>This is a piece of app2 message!</h1>
        <test-cpn/>
    </div>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
        //1.创建组件构造器对象
        const TestCpn = Vue.extend({
            // template --> 定义组件的HTML模板
            template: `
            <div>
                <h2>组件标题</h2>
                <p class="some-style">组件内容</p>
                {{mes}}
                <button @click="handleBtn">点我你就知道了</button>
            </div>
            `,
            // data --> 用于存放组件的数据
            data() {
                return {
                    mes: 'hello vue component!'
                }
            },
            // methods --> 组件的方法都写到这里面
            methods: {
                handleBtn() {
                    console.log('这不就是组件的行为了吗?讨厌!')
                }
            }
        })
        //2.注册组件
        // Vue.component('组件的标题','构造器对象')
        Vue.component('test-cpn', TestCpn);
        const vm = new Vue({
            el: '#app'
        })
        const vm2 = new Vue({
            el: '#app2'
        })
    </script>
</body>
</html>

在这里插入图片描述

  那怎么使用局部组件呢?那就是在实例里边注册组件。

  如下例子:当我们在实例vm里边注册TestCpn组件,那么在实例vm2里使用TestCpn组件时,它就会报错,且没有数据展示到页面上。这是因为实例vm2找不到TestCpn组件。因为它是在实例vm定义的嘛!所以这就是局部组件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件化基本使用</title>
    <style>
        .some-style{
            color: red;
            font-size: 20px;
            font-weight: bolder;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>This is a piece of app message!</h1>
        <!-- 3.使用组件 -->
        <test-cpn></test-cpn>
        <test-cpn></test-cpn>

        <!-- 使用单标签 -->
        <test-cpn/>
    </div>

    <div id="app2">
        <hr>
        <h1>This is a piece of app2 message!</h1>
        <test-cpn/>
    </div>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
        //1.创建组件构造器对象
        const TestCpn = Vue.extend({
            // template --> 定义组件的HTML模板
            template: `
            <div>
                <h2>组件标题</h2>
                <p class="some-style">组件内容</p>
                {{mes}}
                <button @click="handleBtn">点我你就知道了</button>
            </div>
            `,
            // data --> 用于存放组件的数据
            data() {
                return {
                    mes: 'hello vue component!'
                }
            },
            // methods --> 组件的方法都写到这里面
            methods: {
                handleBtn() {
                    console.log('这不就是组件的行为了吗?讨厌!')
                }
            }
        })
        const vm = new Vue({
            el: '#app',
            //2.在vm实例里面 注册组件
            // component('组件的标题','构造器对象')
            components: {
                'test-cpn': TestCpn
            }
        })
        const vm2 = new Vue({
            el: '#app2'
        })
    </script>
</body>
</html>

在这里插入图片描述

  其实有个问题,我们在注册组件的时候(Vue.component('组件的标题', '构造器对象')) component的第二个参数不是要传一个构造器对象吗? 那我们传给它好了,直接传一个选项对象,不用我们亲自去调用extend方法,因为Vue会帮我们去调用它,所以我们完全可以这样写:

Vue.component('test-cpn', { /* ... */ })

  注册全局组件就是这样写:

el: 'app',
data() {
    return{
        ....
    }
},
component: {
    'test-cpn': {/* ... */ }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件化基本使用</title>
    <style>
        .some-style{
            color: red;
            font-size: 20px;
            font-weight: bolder;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>This is a piece of app message!</h1>
        <!-- 3.使用组件 -->
        <test-cpn></test-cpn>
        <test-cpn></test-cpn>

        <!-- 使用单标签 -->
        <test-cpn/>
    </div>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            //2.注册组件
            // Vue.component('组件的标题','构造器对象')
            components: {
                'test-cpn': {
                    // template --> 定义组件的HTML模板
                    template: `
                    <div>
                        <h2>组件标题</h2>
                        <p class="some-style">组件内容</p>
                        {{mes}}
                        <button @click="handleBtn">点我你就知道了</button>
                    </div>
                    `,
                    // data --> 用于存放组件的数据
                    data() {
                        return {
                            mes: 'hello vue component!'
                        }
                    },
                    // methods --> 组件的方法都写到这里面
                    methods: {
                        handleBtn() {
                            console.log('这不就是组件的行为了吗?讨厌!')
                        }
                    }
                }
            }
        })
    </script>
</body>
</html>

  当然,这样写代码结构乱七八糟的,我们应该把html代码抽离出去,这样html代码和js代码不会混在一起了,看着也是舒服一点。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件化基本使用</title>
    <style>
        .some-style{
            color: red;
            font-size: 20px;
            font-weight: bolder;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>This is a piece of app message!</h1>
        <!-- 3.使用组件 -->
        <test-cpn></test-cpn>
        <test-cpn></test-cpn>

        <!-- 使用单标签 -->
        <test-cpn/>
    </div>
    <!-- vue组件结构模板 -->
    <template id="test-cpn">
        <div>
            <h2>组件标题</h2>
            <p class="some-style">组件内容</p>
            {{mes}}
            <button @click="handleBtn">点我你就知道了</button>
        </div>
    </template>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            //2.注册组件
            // Vue.component('组件的标题','构造器对象')
            components: {
                'test-cpn': {
                    // template --> 定义组件的HTML模板
                    template: '#test-cpn',
                    // data --> 用于存放组件的数据
                    data() {
                        return {
                            mes: 'hello vue component!'
                        }
                    },
                    // methods --> 组件的方法都写到这里面
                    methods: {
                        handleBtn() {
                            console.log('这不就是组件的行为了吗?讨厌!')
                        }
                    }
                }
            }
        })
    </script>
</body>
</html>

在这里插入图片描述

  丝毫不影响我们程序运行、而且代码看起来也舒舒服服的~

组件通信

父传子

  现在我们知道组件有data、有methods、有computedwatch、等。其实组件还有一个重要的属性props

  propsdata差不多,是用于存放组件中用到的数据的,但是props中的数据是从父组件中传递过来的,并且只能在父组件中修改props中的数据,子组件只能用props中的数据,不能直接修改props中的数据。data中的数据是组件自己定义的。组件也可以直接修改data中的数据。

  哪个是父组件?哪个又是子组件呢?在上面例子中,test-cpn 就是子组件, vm 实例就是父组件,因为我们在 vm 实例上注册了 test-cpn 组件并且使用它。

  那如何从父组件传递数据呢?show code!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件化基本使用</title>
    <style>
        .some-style{
            color: red;
            font-size: 20px;
            font-weight: bolder;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>This is a piece of app message!</h1>
        <!-- 3.使用组件,并且送给它一段话 -->
        <test-cpn msg="我是你爹!"></test-cpn>
        <!-- 3.使用组件,我没什么要给它的 -->
        <test-cpn></test-cpn>

        <!-- 使用组件,使用单标签,我也没什么要给它的 -->
        <test-cpn/>
    </div>
    <!-- vue组件结构模板 -->
    <template id="test-cpn">
        <div>
            <h2>组件标题</h2>
            <p class="some-style">组件内容</p>
            {{mes}}
            <button @click="handleBtn">点我你就知道了</button>
            <h4>让我看看父组件给我传来了什么消息:{{msg}}</h4>
        </div>
    </template>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            //2.注册组件
            // Vue.component('组件的标题','构造器对象')
            components: {
                'test-cpn': {
                    // template --> 定义组件的HTML模板
                    template: '#test-cpn',
                    // props --> 用于接收从父组件传递来的数据
                    props: ['msg'],
                    // data  --> 用于存放组件的数据
                    data() {
                        return {
                            mes: 'hello vue component!'
                        }
                    },
                    // methods --> 组件的方法都写到这里面
                    methods: {
                        handleBtn() {
                            console.log('这不就是组件的行为了吗?讨厌!')
                        }
                    }
                }
            }
        })
    </script>
</body>
</html>

在这里插入图片描述

  看吧!就是这么简单,只需要在父组件中使用子组件时,写一个属性和值就可以了。属性就是在子组件定义好的数据,值就是你想要传的数据。上述例子中,我们在父组件使用了三次 test-cpn 组件,但是只有第一次使用的时候传递msg,而第二次和第三次使用的时候都没有传递msg,所以第一次的时候才会出现msg的数据,而第二次和第三次并没有出现。

  props只能接收字符串吗?呵,它可不止这么简单,它还可以接收数字、数字、对象,而且还可以对要传递的数据进行类型限制、默认值,等校验。也可以动态传递。

props有两种写法:如果对从组件传递的数据不需要类型限制等校验,那么props写成数组形式就好了;如果对从组件传递的数据需要类型限制等校验,那么props就要写成对象形式

// 不需要校验时
props: ['a', 'b', 'c']
// 需要校验时
props: {
    a: {...},
    b: {...},
    c: {...}
} 

  不校验的写法我们已经写过了,接下来就是不校验的写法了

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件化基本使用</title>
    <style>
        .some-style{
            color: red;
            font-size: 20px;
            font-weight: bolder;
        }
    </style>
</head>
<body>
    <div id="app">
      <h1>This is a piece of app message!</h1>
      <!-- 3.使用组件,并且送给它一段话 -->
      <test-cpn msg="我是你爹!"></test-cpn>
      <!-- 3.使用组件,并且动态传递了一个数组给它-->
      <test-cpn :fm="fourMasterpieces"></test-cpn>

      <!-- 使用组件,使用单标签,我也没什么要给它的 -->
      <test-cpn/>
    </div>
    <!-- vue组件结构模板 -->
    <template id="test-cpn">
      <div>
        <h2>组件标题</h2>
        <p class="some-style">组件内容</p>
        {{mes}}
        <button @click="handleBtn">点我你就知道了</button>
        <h4>让我看看父组件给我传来了什么消息:{{msg}}</h4>
        <ul>
          <li v-for="item in fm">{{item}}</li>
        </ul>
      </div>
    </template>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
      const vm = new Vue({
        el: '#app',
          data: {
            fourMasterpieces: ['西游记', '三国演义', '水浒传', '红楼梦']
          },
        //2.注册组件
        // Vue.component('组件的标题','构造器对象')
        components: {
          'test-cpn': {
           // template --> 定义组件的HTML模板
          template: '#test-cpn',
          // props --> 用于接收从父组件传递来的数据
          props: {
            msg: {
              type: String, // 类型限制
              default: '我是默认滴数据' // 默认值
            },
            fm: {
              type: Array // 类型限制
            }
          },
          // data  --> 用于存放组件的数据
          data() {
            return {
              mes: 'hello vue component!'
            }
          },
          // methods --> 组件的方法都写到这里面
          methods: {
            handleBtn() {
              console.log('这不就是组件的行为了吗?讨厌!')
            }
          }
        }
      }
    })
  </script>
</body>
</html>

在这里插入图片描述

  当我们进行类型等校验之后,父组件传的数据类型不对,数据还是能显示出来,但就会报错。 一下代码我只截取一部分

<div id="app">
    <h1>This is a piece of app message!</h1>
    <!-- 3.使用组件,并且送给它一段话 -->
    <test-cpn msg="我是你爹!" :count="num"></test-cpn>
    <!-- 3.使用组件,并且动态传递了一个数组给它-->
    <test-cpn :fm="fourMasterpieces"></test-cpn>

    <!-- 使用组件,使用单标签,我也没什么要给它的 -->
    <test-cpn/>
</div>
<!-- vue组件结构模板 -->
<template id="test-cpn">
    <div>
    <h2>组件标题</h2>
    <p class="some-style">组件内容</p>
    {{mes}}
    <button @click="handleBtn">点我你就知道了</button>
    <h4>让我看看父组件给我传来了什么消息:{{msg}}{{count}}</h4>
    <ul>
        <li v-for="item in fm">{{item}}</li>
    </ul>
    </div>
</template>
data: {
  num: '100',
  fourMasterpieces: ['西游记', '三国演义', '水浒传', '红楼梦']
},

在这里插入图片描述

  这是就可以写多个可能的类型,这样就不对报错了!

props: {
  ...
  count: {
    type: [Number, String]
  },
  ...
}

  也可以设置必传数据,如果设置必传数据,那每一次使用都要传,如果父组件不传就会报错。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件化基本使用</title>
    <style>
        .some-style{
            color: red;
            font-size: 20px;
            font-weight: bolder;
        }
    </style>
</head>
<body>
    <div id="app">
      <h1>This is a piece of app message!</h1>
      <!-- 由于parentName是必须数据, 所以每次有的时候都要传进去 -->
      <!-- 3.使用组件,并且送给它一段话,并且传了动态数据,-->
      <test-cpn msg="我是你爹!" :count="num" :parent-name="name"></test-cpn>
      <!-- 3.使用组件,并且动态传递了两个数组给它-->
      <test-cpn :fm="fourMasterpieces" :parent-name="name"></test-cpn>

      <!-- 3.使用组件,使用单标签,并且传了动态数据 --->
      <test-cpn :parent-name="name"/>
    </div>
    <!-- vue组件结构模板 -->
    <template id="test-cpn">
      <div>
        <h2>组件标题</h2>
        <p>我的爸爸叫:{{parentName}}</p>
        <p class="some-style">组件内容</p>
        {{mes}}
        <button @click="handleBtn">点我你就知道了</button>
        <h4>让我看看父组件给我传来了什么消息:{{msg}}{{count}}</h4>
        <ul>
          <li v-for="item in fm">{{item}}</li>
        </ul>
      </div>
    </template>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
      const vm = new Vue({
        el: '#app',
          data: {
            num: '100',
            name: 'vm实例',
            fourMasterpieces: ['西游记', '三国演义', '水浒传', '红楼梦']
          },
        //2.注册组件
        // Vue.component('组件的标题','构造器对象')
        components: {
          'test-cpn': {
           // template --> 定义组件的HTML模板
          template: '#test-cpn',
          // props --> 用于接收从父组件传递来的数据
          props: {
            msg: {
              type: String, // 类型限制
              default: '我是默认滴数据' // 默认值
            },
            count: {
              type: [Number, String]
            },
            fm: {
              type: Array // 类型限制
            },
            parentName: {
              type: String,
              required: true // 是否必须传递
            }
          },
          // data  --> 用于存放组件的数据
          data() {
            return {
              mes: 'hello vue component!'
            }
          },
          // methods --> 组件的方法都写到这里面
          methods: {
            handleBtn() {
              console.log('这不就是组件的行为了吗?讨厌!')
            }
          }
        }
      }
    })
  </script>
</body>
</html>

在这里插入图片描述

  上面说过在组件里面不能直接修改props中的值,我来添加一个按钮,点击按钮改变props中的count为0,它依然能改变,但是报错了,Vue大概意思是不能在组件里直接修改props中的状态。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件化基本使用</title>
    <style>
        .some-style{
            color: red;
            font-size: 20px;
            font-weight: bolder;
        }
    </style>
</head>
<body>
    <div id="app">
      <h1>This is a piece of app message!</h1>
      <!-- 3.使用组件,并且送给它一段话,并且传了动态数据 -->
      <test-cpn msg="我是你爹!" :count="num" :parent-name="name"></test-cpn>
      <!-- 3.使用组件,并且动态传递了两个数组给它-->
      <test-cpn :fm="fourMasterpieces" :parent-name="name"></test-cpn>

      <!-- 使用组件,使用单标签,并且传了动态数据 --->
      <test-cpn :parent-name="name"/>
    </div>
    <!-- vue组件结构模板 -->
    <template id="test-cpn">
      <div>
        <h2>组件标题</h2>
        <p>我的爸爸叫:{{parentName}}</p>
        <p class="some-style">组件内容</p>
        {{mes}}
        <button @click="handleBtn">点我你就知道了</button>
        <button @click="changePropsValue">修改props中的值</button>
        <h4>让我看看父组件给我传来了什么消息:{{msg}}{{count}}</h4>
        <ul>
          <li v-for="item in fm">{{item}}</li>
        </ul>
      </div>
    </template>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
      const vm = new Vue({
        el: '#app',
          data: {
            num: '100',
            name: 'vm实例',
            fourMasterpieces: ['西游记', '三国演义', '水浒传', '红楼梦']
          },
        //2.注册组件
        // Vue.component('组件的标题','构造器对象')
        components: {
          'test-cpn': {
           // template --> 定义组件的HTML模板
          template: '#test-cpn',
          // props --> 用于接收从父组件传递来的数据
          props: {
            msg: {
              type: String, // 类型限制
              default: '我是默认滴数据' // 默认值
            },
            count: {
              type: [Number, String]
            },
            fm: {
              type: Array // 类型限制
            },
            parentName: {
              type: String,
              required: true // 是否必须
            }
          },
          // data  --> 用于存放组件的数据
          data() {
            return {
              mes: 'hello vue component!'
            }
          },
          // methods --> 组件的方法都写到这里面
          methods: {
            handleBtn() {
              console.log('这不就是组件的行为了吗?讨厌!')
            },
            changePropsValue() {
              this.count = 0
            }
          }
        }
      }
    })
  </script>
</body>
</html>

在这里插入图片描述

子传父

  既然有父传子,那么就有子传父。子传父稍微比父传子更复杂一点,当时我我在学的时候,脑子也是嗡嗡的,后面多敲一点就好了,其实不复杂,等你多敲几遍,那你就会觉得跟呼吸一样简单。说白了,子传父就是发射一个自定义事件。

  上述例子,直接在组件中修改props中的状态,是不行滴~由于props中的数据是从父组件中传过来的,所以应当在父组件中修改它才是最棒的方式!所以可以在子组件中发射一个自定义事件,然后在父组件中使用这自定义事件可以改变传递的数据,数据一改变,子组件就会第一时间收到新的数据。show code!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件化基本使用</title>
    <style>
        .some-style{
            color: red;
            font-size: 20px;
            font-weight: bolder;
        }
    </style>
</head>
<body>
    <div id="app">
      <h1>This is a piece of app message!</h1>
      <!-- 3.使用组件,并且送给它一段话,并且传了动态数据,
             并接收了自定义事件 -->
      <test-cpn
        msg="我是你爹!"
        :count="num"
        :parent-name="name"
        @change-props-value="hanldeValue"
        ></test-cpn>
      <!-- 3.使用组件,并且动态传递了两个数组给它-->
      <test-cpn :fm="fourMasterpieces" :parent-name="name"></test-cpn>

      <!-- 使用组件,使用单标签,并且传了动态数据 --->
      <test-cpn :parent-name="name"/>
    </div>
    <!-- vue组件结构模板 -->
    <template id="test-cpn">
      <div>
        <h2>组件标题</h2>
        <p>我的爸爸叫:{{parentName}}</p>
        <p class="some-style">组件内容</p>
        {{mes}}
        <button @click="handleBtn">点我你就知道了</button>
        <button @click="changePropsValue">修改props中的值</button>
        <h4>让我看看父组件给我传来了什么消息:{{msg}}{{count}}</h4>
        <ul>
          <li v-for="item in fm">{{item}}</li>
        </ul>
      </div>
    </template>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
      const vm = new Vue({
        el: '#app',
          data: {
            num: '100',
            name: 'vm实例',
            fourMasterpieces: ['西游记', '三国演义', '水浒传', '红楼梦']
          },
          // vm实例方法的集合
          methods: {
            hanldeValue(){
              this.num--;
            }
          },
          //2.注册组件
          // component('组件的标题','构造器对象')
          components: {
            'test-cpn': {
             // template --> 定义组件的HTML模板
            template: '#test-cpn',
            // props --> 用于接收从父组件传递来的数据
            props: {
              msg: {
                type: String, // 类型限制
                default: '我是默认滴数据' // 默认值
              },
              count: {
                type: [Number, String]
              },
              fm: {
                type: Array // 类型限制
              },
              parentName: {
                type: String,
                required: true // 是否必须
              }
            },
            // data  --> 用于存放组件的数据
            data() {
              return {
                mes: 'hello vue component!'
              }
            },
            // methods --> 组件的方法都写到这里面
            methods: {
              handleBtn() {
                console.log('这不就是组件的行为了吗?讨厌!')
              },
              changePropsValue() {
                // $emit --> 发射自定义事件
                this.$emit('change-props-value')
              }
            }
          }
        }
      })
    </script>
</body>
</html>

  上述例子给子组件’(修改props中的值)'按钮绑定一个点击事件(changePropsValue),然后在事件处理中我们通过this.$emit发发射一个自定义事件change-props-value。然后在父组件中接收change-props-value自定义事件,通过hanldeValue方法修改父组件中num的值,num的值一改变,子组件就会第一时间收到改变后的值,直接渲染到页面了。

值得注意的是,这里的自定义事件我为什么不写小驼峰命名呢?这里官网说了,HTML 是大小写不敏感的,所以他推荐我们使-代替 小驼峰

在这里插入图片描述

  当然,子组件在发射自定义事件时,也可以传递参数,直接this.$emit('事件名', 一些参数, 另外的一些参数) 传递参数

changePropsValue() {
  // $emit --> 发射自定义事件
  this.$emit('change-props-value', 10)
}
<!-- 3.使用组件,并且送给它一段话,并且传了动态数据,
              并接收了自定义事件 -->
<test-cpn
  msg="我是你爹!"
  :count="num"
  :parent-name="name"
  @change-props-value="hanldeValue"
  ></test-cpn>

// 直接在hanldeValue方法接收参数
hanldeValue(data) {
  console.log(data);
  this.num -= data;
}

在这里插入图片描述
  学到这里是不是感觉脑子乱七八糟的,懵逼是正常的,动动您的手敲几遍,你就会发现突然豁然开朗!还不快去 !打!代!码!,最后再送你一张图:
在这里插入图片描述

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值