更新于

Vue 组件

发布于 / 分类: vue 基础 / 暂无评论 / 阅读量: 662

组件创建注册

vue通过组件可以达到重复利用,有点类似jq的插件,但是又不同,组件需要先创建再注册,注册后再到html里引用,组件又分全局和局部。

全局组件注册

var myTitle = Vue.extend({
    template : '<h2>我是一个全局的标题组件</h2>'
});

Vue.component('my-title',myTitle);

var app = new Vue({
    el : '#app'
});
<div id="app">
    <my-title></my-title>
</div>

component第一个参数就是自定义的组件名字,w3c对组件名要求是必须小写,并且带一个‘-’短横杠,vue并没有具体要求,不过建议大家创建的时候还是按照w3c标准书写。

extend里传入一个对象,tempate里面存储html信息,除了这个template,组件其实拥有vue实例的大部分内容,比如data这些,我们晚点再说。

局部注册

在局部注册的组件无法在其他地方使用。

var myTitle = Vue.extend({
    template : '<h2>我是一个全局的标题组件</h2>'
});

//Vue.component('my-title',myTitle);

var app = new Vue({
    el : '#app',
    template : '<div>\
        <h2>这是局部组件</h2>\
        <my-title></my-title>\
        </div>',
    components : {
        'my-title' : myTitle
    }
});
<div id="app">
   
</div>

在vue的实例里添加template,vue会将app元素的内容替换成template的内容,哪怕app这个div已经有内容了(里面写了组件元素)依旧会template内容给全部替换掉。

在vue实例里注册一个my-title,他对应extend创建的组件,然后在template里面可以调用。

在js里,如果你的string要换行书写方便浏览,需要在每一行的后面加上一个反斜杠,不然换行后无法被认为是string值。

注册语法糖

如果每次都要exted创建,然后component注册,实在是太麻烦了,所以提供了简化的办法。

Vue.component('my-title',{
    template : '<h2>语法糖创建全局组件</h2>'
});

var app = new Vue({
    el : '#app',
    components : {
        'my-p' : {
            template : '<p>语法糖注册的局部组件</p>'
        }
    }
});
<div id="app">
    <p>已经有内容了</p>
    <my-title></my-title>
    <my-p></my-p>
</div>

可以直接用component来一口气搞定,需要注意的是,component在局部里使用要加上s。

组件选项

组件拥有大部分和vue实例相同的属性内容,比如之前说的data,el,需要注意的是el和data在组件里需要通过一个函数return出来,因为组件的复用性,他的data成了一个引用对象,如果一个地方改了,其他地方也会修改,但是这并不是我们想要的结果,所以通过一个函数返回出来,就是独立的了。

Vue.component('my-title',{
    data(){
        return {
            name : '全局的独立data'
        }
    },
    template : '<h2>语法糖创建全局组件</h2>'
});

el也是这样,但是el一般来说用不到,我也没遇到过组件里使用el的,这个以后遇到了再来详解。

props子组件接收父组件参数

由于组件是是一个独立的作用域,父子组件,子子组件之间是无法进行通信的,所以这里就需要props属性了。

props是一个数组参数,可以自定义创建多个接受用的名。

Vue.component('my-title',{
    data(){
        return {
            name : '全局的独立data'
        }
    },
    props : ['value1','value2'],
    template : '<h2>这是我使用props接收的第一个参数:{{value1}},这是第二个{{value2}}</h2>'
});
<div id="app">
  <p>已经有内容了</p>
  <my-title value1="第一个参数哦" value2="第二个参数哦"></my-title>
  <my-p></my-p>
</div>

基本上就是props创建的名要在调用的自定义html标签上写成对应的键值对参数。然后子组件通过插值的方式将接受到的参数获取到。

动态参数

除了刚刚的传一个固定的值,还可以绑定父组件的内容,这样发生变化子组件也会更新

Vue.component('my-title',{
    data(){
        return {
            name : '全局的独立data'
        }
    },
    props : ['value1','value2'],
    template : '<h2>这是我使用props接收的第一个参数:{{value1}},这是第二个{{value2}}</h2>'
});

var app = new Vue({
    el : '#app',
    data : {
        ms1 : '动态参数1哦',
        ms2 : '动态参数2哦'
    },
    components : {
        'my-p' : {
            template : '<p>语法糖注册的局部组件</p>'
        }
    }
});
<div id="app">
    <p>已经有内容了</p>
    <my-title :value1="ms1" :value2="ms2"></my-title>
    <my-p></my-p>
</div>

通过v-bind就可以绑定成动态参数了。

驼峰命名

如果你的props创建的名是一个驼峰式的,那么在html标签书写时要把大写改为小写,并且在大写的字符前加’-‘断横杠。

如:

props : ['myTitle']

<my-title :my-title="驼峰命名"></my-title>

通过props绑定父实例的参数才可以传递各种格式的内容,不然只能传递string类型。

props绑定类型

在动态绑定中,v-bind也提供了几种修饰符也进行不同方式的绑定,一般来说,子组件通过绑定父组件的数据,父组件进行修改后会影响到子组件的内容,但是子组件修改内容并不会影响到父组件,如果想要子组件影响到父组件,可以使用修饰符。

  1. .sync 双向绑定,类似于v-model
  2. .once 单次绑定,表示子组件接收一次父组件的数据后独立维护,互不相干

绑定的使用方式其实就是在v-bind后面加上修饰符,如v-bind.sync:props="xxx",这样绑定子组件props声明的接受参数的变量名,然后绑定父组件的数据,当子组件的内容发生变化也会影响到父组件。

once就很简单了,只接受一次参数。

很可惜的是这两个修饰符在2.0被移除了,但是有一个特性依旧存在,就是加入我们接受的参数是一个对象,对象都是引用类型,所以这个对象在子元素操作后也会影响到父元素,类似于sync的效果,但是不建议这么使用。

props验证

由于从父组件接受的参数不确定性,你不知道你写的这个组件会不会在被人复用的时候传入的是指定的参数类型,所以vue提供了一个参数验证。

  1. 基础检测类型:String、Number、Boolean、Function、Object、Array。也可接受 null,意味任意类型均可。
  2. 多种类型:[Number, String],通过一个数组将需要验证的类型写在里面】
  3. 必须传参: required: true
  4. 默认参数:default : 10 如果没有参数传入,使用默认参数
var app = new Vue({
    el : '#app',
    data : {
        ms1 : '动态参数1哦',
        ms2 : '动态参数2哦'
    },
    components : {
        'my-input' : {
            template : '<input type="text" v-model="sny" />',
            props : {
                sny1 : [Number, String],
                sny2 : {
                    type : [Number, String],
                    required : true
                },
                sny3 : {
                    type : Number,
                    default : 10
                }
            }
        }
    }
});

基本就这三种写法,单一的指定类型使用键值对,多个的使用一个对象保存,type为类型,required为必须传参,default 为默认参数。

如果默认参数和必须都存在,就会出现问题,如果没有传参依旧会使用默认值,但是会报错,然后如果传入的参数不对,也会将其进行渲染出来并报错,所以不建议一起混用,并且可以知道这个验证也并不是强制性的。

如果指定的类型是Array或者Object的时候,默认参数default必须是一个函数,然后将内容return出来,以免复用时参数不是独立的。

ms4: {
    type: Array,
    default: function() {
        return ['foo', 'bar'];
    }
}

自定义验证规整

如果验证的内容过于复杂就需要自己写一个验证规则,通过返回true、false来判断是否验证通过。

使用validator参数,他对应一个方法,方法里接收一个参数,这个参数就是传入的值。

ms5: {
    validator: function(value) {
        return value >= 0 && value <= 128;
    }
}

子组件向父组件传参 $emit

props是父组件向子组件传参,而子组件向父组件传参就没办了,所以我们可以通过自定义事件的方式传参。

整个流程是这样的,子组件通过触发某个事件或者方法,方法里使用$emit触发自身的自定义事件,而这个自定义的事件是在html中的,并不是事先在template中写好的,这样这个自定义事件是可以绑定到父组件的方法的,此时,我们通过$emit就可以传入参数,就可以做到从子组件运行父组件的方法,这个参数就和平时调用方法一样,想传几个传几个。

具体上代码:

Vue.component('my-h2',{
    template : '<h2 @click="ceshi">我是一个子组件</h2>',
    methods : {
        ceshi(){
            console.log('1')
            this.$emit('add','s','b');
        }
    }
});

var app = new Vue({
    el : '#app',
    methods : {
        xixi(value1,value2){
            alert(value1+value2);
        }
    }
});
<div id="app">
    <my-h2 @add="xixi"></my-h2>
</div>

子组件click事件绑定本身的ceshi方法,然后在该方法里面触发html绑定的父组件的xixi方法,这样就可以触发到父组件的方法了。

补充

使用 this.$parent查找当前组件的父组件。
使用 this.$children查找当前组件的直接子组件,可以遍历全部子组件, 需要注意 $children 并不保证顺序,也不是响应式的。
使用 this.$root查找根组件,并可以配合$children遍历全部组件。
使用 this.$refs查找命名子组件。

使用这些也可以进行一下父子组件的相互通信。

$refs

vue2.0放弃了v-ref的形式,直接使用ref=“”来进行绑定,通过$refs来获取绑定的元素。

<div id="app">
    <my-h2 @add="xixi" ref="zi"></my-h2>
    <h3 ref="title">sss</h3>
</div>

在需要获取到的子组件使用ref属性,设置一个名字,然后在父组件通过$refs就可以获取到对应的对象,里面包含了对应的dom元素。

slot插值

简单点来说就是,通过在父组件html中,使用slot属性绑定对应的html元素,并指定一个名字,然后在子组件中,通过slot元素和名字就可以将对应的父组件中的html元素替换到子组件中,这样也可以达到传值的效果。

<div id="app">
    <my-h2 @add="xixi" ref="zi">
        <p slot="title">{{title}}</p>
        <span slot="info">{{info}}</span>
    </my-h2>
</div>

p和span都通过slot属性设置了一个name,然后在里面插值了对应的内容。

Vue.component('my-h2',{
    template : '<div @click="ceshi">我是一个子组件 \
            <div><slot name="title"></slot></div> \
            <div><slot name="info"></slot></div> \
        </div>',
    methods : {
        ceshi(){
            console.log('1')
            this.$emit('add');
        }
    }
});

var app = new Vue({
    el : '#app',
    data : {
        title : '标题',
        info : '其他信息'
    },
    methods : {
        xixi(){
            console.log(this.$refs)
        }
    }
});

在组件中,我们可以自定义html的结构,并且使用slot元素,通name=“”来对应父组件slot设置的元素,然后vue渲染的时候,就会将slot元素替换成父组件中对应的html元素。

注意:name的值一定要和html上的slot的值一样才行

编译作用域

在上面,我们的子组件的slot获取到了父组件的data的内容,由此可见,父组件中的html渲染是在父组件的作用域下的,如果你在父作用域下绑定一个子组件的data内容,是无法获取到的,并且会报错。

如:

<div id="app">
    <my-h2 @add="xixi" ref="zi">
        <p slot="title">{{cee}}</p>
        <span slot="info">{{info}}</span>
    </my-h2>
</div>

绑定一个子组件的cee

Vue.component('my-h2',{
    template : '<div @click="ceshi">我是一个子组件 \
            <div><slot name="title"></slot></div> \
            <div><slot name="info"></slot></div> \
        </div>',
    methods : {
        ceshi(){
            console.log('1')
            this.$emit('add');
        }
    },
    data(){
        return {
            cee : 'sdada'
        }
    }
});

var app = new Vue({
    el : '#app',
    data : {
        title : '标题',
        info : '其他信息'
    },
    methods : {
        xixi(){
            console.log(this.$refs)
        }
    }
});

元素依旧会被渲染,但是没有插值的内容,控制台报错。

默认slot

如果你在子组件的自定义标签里面书写了多个标签内容,然后有部分并没有设置slot属性,那么这些没有设置的会在渲染的时候消失,如何让他们显示呢!这里就可以用到默认的slot标签了。

slot标签不写name,就是一个默认的slot标签,该标签如果存在,就会将子组件中所有没有设置slot属性的元素全部都获取到并渲染到子组件中对应的默认标签位置。

<div id="app">
    <my-h2 @add="xixi" ref="zi">
        <h3>{{title}}</h3>
        <h3>我没有slot任何地方</h3>
        <h3>我没有slot任何地方</h3>
    </my-h2>
</div>
Vue.component('my-h2',{
    template : '<div @click="ceshi">我是一个子组件 \
            <div><slot></slot></div> \
        </div>',
    methods : {
        ceshi(){
            console.log('1')
            this.$emit('add');
        }
    },
    data(){
        return {
            cee : 'sdada'
        }
    }
});

var app = new Vue({
    el : '#app',
    data : {
        title : '标题',
        info : '其他信息'
    },
    methods : {
        xixi(){
            console.log(this.$refs)
        }
    }
});

slot属性相同

如果我有多个相同的slot属性,子组件中的slot元素会将相同属性的元素全部获取到,并依次插入,以兄弟元素呈现,并渲染出来。

暂无评论

设置
配色方案

布局

购买