Vue组件基础详解

Vue组件

一.概念

在vue里,一个组件的本质上是一个拥有预定义选项的一个Vue实例

二.组件的使用

  • 定义(注册)组件
  • 调用(使用)组件

将组件就看成是一个函数

1.组件的注册

  • 全局组件注册

    当前Vue项目中,任何组件中都可以去使用

        /**
         * componentName 组件的名字
         * componentOptions 组件的选项配置
        */
        Vue.component(componentName,componentOptions);

    	//com1 全局组件
        Vue.component('com1', {
            template: `<div>
                            我是hello组件
                       </div>`
        });
  • 局部组件注册

    在哪个组件中注册的,就只能使用在哪个组件中

 		
 		 /**
         * 局部组件注册
         * 在组件的components配置选项中去定义
         * new Vue 构造函数 ,生成的实例,一般我们叫它根组件
         * componentName1 局部组件名字
         * componentOptions1 局部组件对应的选项
         * */
		new Vue({
            components:{
                componentName1:componentOptions1
                componentName2:componentOptions2
            }
        });

在组件的components配置选项中去定义

new Vue,生成的实例,一般我们叫它根组件

compontentOptions就是一个对象,里面有配置与new Vue时类似,但有一些例外:

  1. 组件没有el选项,因为后续调用组件在哪里,这个组件的挂载点就是哪里
  2. 必须有template或者render选项,用来规定组件的模版内容
  3. data选项必须是一个函数返回对象的形式

2.组件的调用

将组件名当做自定义的html标签使用即可

		//全局组件注册   		
		Vue.component('hello', {
            // 注意:必须有template和render选项,用来规定组件的模版内容
            template: `<div>我是全局组件hello </div>`
        });

		 //根组件
        var vm = new Vue({
            el: '#app'
        });


		//调用组件 这个div可以看成是根组件的template
		<div id="app">
             <hello></hello>
        </div>

调用时,必须要在根组件里面,我这里的根组件的挂载点是 #app, 这个hello 组件放在了根组件的div中,实际上就是把hello组件的template渲染到了根组件上,那么这里就是 hello组件是 根组件Root的子组件

   		//com1 全局组件
        Vue.component('com1', {
            // 这里,com3是不能用的,会报错,因为com3是com2的子组件,只能在com2中使用
            template: `<div>
                            我是hello组件
                       </div>`
        });

        //com2和com1是全局组件,任何组件都可以使用
        Vue.component('com2', {
            //com3和com4只能在com2中使用,局部组件,只属于com3和com4的子组件
            template:
                `
                <div>
                    我是com2组件
                    <com3></com3>
                </div>`
            ,
            components: {
                'com3': {
                    template: `<div>我是com3组件,只能在com2中使用</div>`
                },
                'com4': {
                    template: `<div>我是com4组件,只能在com2中使用</div>`
                }
            }
        });

        //根组件
        var vm = new Vue({
            el: '#app'
        });

3.组件的复用

	<div id="app">
        <button-counter></button-counter>
        <button-counter></button-counter>
 		<button-counter></button-counter>
        <button-counter></button-counter>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <script>
        // 定义一个名为 button-counter 的新组件
        Vue.component('button-counter', {
            data: function () {
                return {
                    count: 0
                }
            },
            template: '<button v-on:click="count++">你点击了 {{ count }} times.</button>'
        })

        var vm = new Vue({
            el: '#app'
        });
    </script>

定义的全局组件可以在根组件下任意使用多个,进行组件的复用

注意

data必须是一个函数

为什么组件的data选项要写成函数形式呢?

原因是组件是可以进行复用的,如果data直接写成对象,那么复用的时候,会造成数据污染(多个实例对象共用一个变量)

当我们点击上面按钮的时候,因为使用了函数形式的返回data数据,所以每个组件都会各自独立维护它的变量count,y因为每用一个组件,就会有一个新的实例被创建.

4.组件名

组件名不能是现有的html标签名,也不能是之前已经注册过的组件(实际上是可以,只不过会覆盖之前的)

        Vue.component('nav', {
            template: '<button v-on:click="count++">你点击了 {{ count }} times.</button>'
        })

        var vm = new Vue({
            el: '#app'
        });

nav是html5的标签名,这里不能使用,会报错.也不能是 a,button,div之类,总之不能使用现有的html标签名.

组件名的规则:

可以使用短横线写法:

  • hello-world

可以使用驼峰写法

  • HelloWorld

调用组件时,需要使用短横线写法 上述两种,都可以使用hello-world

但是也有例外,以下三种情况可以无视这种规则

1.写在template选项中

		//写在template选项中,可以无视这种规则       
		Vue.component('com1', {
            template: 
           '<div>
               COM1
              <HelloWorld></HelloWorld>
           </div>'
        })

        Vue.component('HelloWorld', {
            template: '<div>HelloWorld</div>'
        })

		//这里又template选项,会覆盖页面上的#app
		//驼峰命名的组件,这里使用驼峰和短横线都可以使用
        var vm = new Vue({
            el: '#app',
            template:
            `<div id='app'>
                <HelloWorld></HelloWorld> 
                <hello-world></hello-world>
                <com1></com1>
             </div>               `
        });

2.写在里面的

我们写了组件这么多代码,特别是在写template选项中的写模版内容代码时,发现非常的不方便,没有语法高亮,也没有代码提示,这时可以将模版内容,放置在一个script标签里面

要注意:

  • 需要设置script 的type属性为text/x-template
  • 给这个script设置一个id

调用时,直接使用template:’#xxxx’即可

    <script id="appTemplate" type="text/x-template">
        <div id='app'>
            <HelloWorld></HelloWorld> 
            <hello-world></hello-world>
            <com1></com1>
         </div> 
    </script>
    <script>

        Vue.component('com1', {
            template: '<div>COM1<HelloWorld></HelloWorld></div>'
        })

        Vue.component('HelloWorld', {
            template: '<div>HelloWorld</div>'
        })

		//调用模版内容
        var vm = new Vue({
            template: `#appTemplate`
        });
    </script>

这种情况时,使用template选项中调用组件,可以无视上面的组件调用规则

3.vue后缀的单文件组件时

5.组件的注意事项

  1. 全局组件注册时,必须要放置在new Vue之前

            Vue.component('com1', {
             template: '<button v-on:click="count++">你点击了 {{ count }} times.</button>'
            })
    
    		//上面定义的全局组件,必须写在new Vue之前,否则会报错
            var vm = new Vue({
                el: '#app'
            });
    
    
    		//这是错误的写法,报错
            var vm = new Vue({
                el: '#app'
            });
    
     		Vue.component('com1', {
             template: '<button v-on:click="count++">你点击了 {{ count }} times.</button>'
            })
    

    2.组件的template模版内容,必须只能有一个根元素.

     <script id="appTemplate" type="text/x-template">
            //调用组件时,必须只能有一个根组件
            <div id='app'>
                <HelloWorld></HelloWorld> 
                <hello-world></hello-world>
                <com1></com1>
             </div> 
        </script>
    
        <script id="appTemplate" type="text/x-template">
         		//这种情况会报错,因为必须只能有一个根元素
                <HelloWorld></HelloWorld> 
                <hello-world></hello-world>
                <com1></com1>
        </script>
    

三.Props选项

将组件看成是一个函数,props就是这个函数接收到的参数集合

prop就是props中具体的一个参数

//这样理解props选项

//定义一个函数,接收props形参
function hello(props){
 
}

//调用hello函数 传递一个对象,给到参数
hello({name:liuqiao,age:18,sex:'男'});

//props指的就是这些个参数集合
props=>{name:liuqiao,age:18,sex:'男'}
name =>prop 这都是其中的一个prop
age  =>prop
sex  =>prop
1.props命名规则

HTML 中的 属性 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符,

如果是在html中写prop时,如果props设置时是使用驼峰命名法,则需要改用短横线

```js
   Vue.component('hello', {
        props: ['postTitle'],
        template: '<div>  我的姓名是:{{ postTitle }} </div>'
    })

	<div id="app">
    	<hello post-title='liuqiao'></hello>
	</div>
```

注意,这里的props命名规则与组件名命名的规则一样,也有三种情况可以无视这种规则

  • 写在template选项中
  • 写在里面的
  • vue后缀的单文件组件时

官网的说明是:使用字符串模板,那么这个限制就不存在了。

2.设置props

组件定义时,如何设置形参?就是设置props选项

最简单的方式就是:写成数组形式,数组中每一项就是一个prop

定义的每一个prop,可以直接通过实例对象去访问到,就像访问data数据和computed数据一样

 	Vue.component('hello', {
            //props选项:写成数组形式,数组中每一项就是一个prop
            props: ['name', 'age', 'sex'],
        
            template: `
                <div> 
                    我的姓名是:{{ name }},我的年龄:{{age}}
                    <button @click="hi('abc')">点我</button>
                </div>
               
            `,
            methods:{
                hi(a){
                    console.log(this.name+this.age+a);
                    console.log(this.sex);//不传递sex参数时,打印结果是undefined
                }
            }
        })

3.传递参数

调用组件时,在组件上的标签上写属性即可

注意:调用时:不传递参数是没有问题的

 		//调用模版内容
        var vm = new Vue({
            el:'#app',
            template: `
             <div id="app">
                <hello name='liuqiao' age='19'></hello>
             </div>
            `
        });

如:

​ hello组件上name就是liuqiao

​ hello组件上age就是19

​ hello组件上sex没有传递,是undefined

4.props的默认值

如果调用组件时,没有传递某个prop下来,那么组织中的这个prop的值是undefined

设置props默认值:也就是调用时如果没有传递某prop,那我就使用默认值

类似函数中es6的设置默认值

es6中函数设置默认值

funciton hello(name='liuqiao'){
    
}
hello();

在组件中给props设置默认值>关键点是:将数组格式的props改成对象格式

 	  props:{
            key1:{
                type:String,
                default:'liuqiao'
            },
            key2:{
                type:Number,
                default:18
            }
        }

key1,key2就是props的名字
type:是接收这个参数的数据类型
default:是这个prop的默认值

  	Vue.component('hello', {
            props: {
                'name':{
                    type:String,
                    default:'zhangsan'
                },
                'age':{
                    type:Number,
                    default:18
                }
            },
            template: `
                <div> 
                    我的姓名是:{{ name }},我的年龄:{{age}}
                </div>
				`
        })

        var vm = new Vue({
            el: '#app',
            template: `
             <div id="app">
                <hello></hello>
             </div>
            `
        });
5.props的校验

如果调用组件时,我希望可以保证你传过来的prop是有效的,所以需要设置 正确的数据类型

比如我在组件中规定,你需要传递string类型的参数,你就必须传递string类型,否则报错

这叫做props的类型校验

官网的例子是这样的:

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

我这边自己也就是总结了4中写法:

​ 1.直接写需要的类型

​ 2.写成对象形式

​ 3.写成数组形式(意思是string和number都可以接收)

 		props:{
            key:String  //第一种
            key:{
                type:String //第二种
            }
            key:[String,Number],//第三种
                
            //第四种,自定义验证函数
            key:{
                abc:function(){
                    
                }
            }
        }

其中type类型可以有以下几种:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

另外,传递prop的时候,默认都是字符串格式,需要转化的话,只需加上 v-bind 即可

  Vue.component('hello', {
            props: {
                'name':String,
                'age':{
                    type:Number
                },
                'sex':[String,Number]
            },
            template: `
                <div> 
                    我的姓名是:{{ name }},我的年龄:{{age}}
                </div>
            `
        })


        //调用模版内容
        var vm = new Vue({
            el: '#app',
            template: `
             <div id="app">
                <hello name='liuqiao'></hello>
                <hello :age='18'></hello>
                <hello sex='男'></hello>
             </div>
            `
        });

v-bind可以省略,直接使用冒号 : 即可

6.传递动态的props

传入一个对象所有需要的属性

  		Vue.component('hello', {
            props: {
                name: String,
                age: Number
            },
            template: `
                <div> 
                    我的姓名是:{{ name }},我的年龄:{{age}}
                </div>
            `
        })


        //调用模版内容
        var vm = new Vue({
            el: '#app',
            data: {
                userinfo: {
                    name: 'liuqiao',
                    age: 28
                }
            },
            template: `<hello v-bind='userinfo'></hello>`
        });

调用组件时,直接属性上写v-bind=

<hello v-bind='userinfo'></hello>

实际上,这种写法等价于

<hello v-bind:name='userinfo.name' v-bind:age='username.age'></hello>
7.Props单向数据流

单向数据流:props传递参数时,都是单向下行绑定的.父组件的prop会向下传递到子组件,反过来不行

所有的prop都使得其父子prop之间形成了一个单向下行绑定.父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

上面一段是官网的原话.总结一句话就是:不要去直接修改prop传过来的数据

一般有两种情况改变prop

  • 父组件传过来的初始值 通过props传过来的,子组件想作为自己本地存储

    props:{
        msg:{
            type:String,
            required:true
        }
    },
    data(){
        return{
            msgInfo:this.msg;
        }
    }
    

    这种方式,就是在本地声明一个属性,然后初始化去接收,作为本地存储,就不会修改prop了

  • 父组件传过来的初始值,通过props传过来,然后需要自己做转换

    props:{
        msg:{
            type:String,
            required:true
        }
    },
    computed:{
        newMsg:function(){
            return this.msg.trim().toLowerCase()
        }
    }
    

    这种方式,就是通过一个计算属性去处理

猜你喜欢

转载自blog.csdn.net/liuqiao0327/article/details/106368944