欢迎来到Cecilia陈的博客

孤独,是人一生最好的修行。

05 Vue组件

一、组件的概念

每一个组件都是一个vue实例
每个组件均具有自身的模板template,根组件的模板就是挂载点
每个组件模板只能拥有一个根标签
子组件的数据具有作用域,以达到组件的复用

二、根组件

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <div id="app">
        <p>{{ msg }}</p>
    </div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
    /**
     * 1、组件:由html、css、js三部分组成的独立单位,可以类似于变量,重复使用
     * 2、组件其实就是vue实例(对象),一个组件就是一个vue实例(对象)
     * 3、new Vue()产生的也是实例(对象),所以也是组件,我们称之为 根组件
     *      一个页面建议只出现一个根组件(项目开发模式下,一个项目建议只出现一个根组件)
     * 4、组件的html页面结构有 template 实例成员提供
     *      template提供的html结构是用来构虚拟DOM
     *      真实DOM最终会被虚拟DOM替换
     *      根组件一般不提供template,就由挂载点el来提供构建虚拟DOM的页面结构,根组件如果提供了template,还需要设置挂载点作为替换占位
     *      template模板有且只有一个根标签
     */
    let c1 = '';
    new Vue({
        el: '#app',
        data: {
            msg: '12345', // 此时msg只会渲染Vue实例中自定义的虚拟的dom
            c1: 'red'
        },
        template: `
        <div id="app">
            <p :style="{color: c1}">{{ msg }}</p>
            <p @click="clickAction">{{ msg }}</p>
        </div>
        `,
        methods: {
            clickAction() {
                this.msg='56789'
            }
        }
    })
</script>
</html>

三、子组件

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>子组件</title>
</head>
<body>
    <!--根组件的template-->
    <div id="app">
        <!--在根组件template中加载的组件,称之为根组件的子组件-->
        <my-tag></my-tag>
        <my-tag></my-tag>
        <my-tag></my-tag>
		
        <!--这里是我们定义的全局组件-->
        <tag></tag> 
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    // 1、定义组件
    // 2、注册组件
    // 3、使用组件

    // 如何定义子组件:组件就是一个普通对象,内部采用vue语法结构,被vue注册解释后,就会成为vue组件
    let myTag = {
        template: `
        <div>
            <h3>子组件</h3>
            <p>我是自定义的子组件</p>
        </div>
        `,
    };

    // 了解:全局组件,不要注册就可以直接使用
    Vue.component('tag', {
        template: `
        <div>
            <h3>全局组件</h3>
            <p>我是自定义的全局组件</p>
        </div>
        `,
    });

    new Vue({
        el: '#app',
        // 将上面自定义的dom对象,在Vue实例中注册
        components: {
            // 'my-tag': myTag,
            // myTag: myTag,
            myTag,
        }
    })
</script>
</html>

四、局部组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body{
            user-select:none ;
        }
        .wrap{
            width:calc(200px*4 + 100px);
            margin: auto auto;

        }
        .imgs{
            width: 200px;
            height: 250px;
            background-color: #dca7a7;
            margin: 10px;
            display: inline-block;
            text-align: center;
        }
        img{
            width: 200px;
        }

    </style>
</head>
<body>
    <div id="app">
        <div class="wrap">
            <mytag></mytag>
            <mytag></mytag>
            <mytag></mytag>
            <mytag></mytag>
        </div>
    </div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
    let mytag = {
        template:`
            <div class="imgs">
                <img src="img/dog.jpg" alt="">
                <p>品种:二哈</p>

				// 这里的count是子组件中的定义的,所以要提前在子组件中声明,
                <p @click="clickEvent" style="cursor: pointer">点击:{{count}}次</p>
            </div>
        `,
        // 当子组件中有位置的变量的时候,会自动调用data这个方法
        // 子组件中声明子组件的方式,data() 内部会返回count的值
        data(){
            return {
                count:0
            }
        },
        methods:{
            clickEvent(){
                this.count++
            }
        }
    };

    new Vue({
        el:'#app',
        components:{
            mytag,
        }
    })
</script>
</html>

五、父子组件间传递数据

1. 父组件向子组件传递数据

通过绑定属性的方式进行数据传递

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body{
            user-select:none ;
        }
        .wrap{
            width:calc(200px*4 + 100px);
            margin: auto auto;
        }
        .box{
            width: 200px;
            height: 300px;
            background-color:#dca7a7;
            margin:10px;
            float: left;
            text-align: center;
        }
        img{
            width: 200px;
            border-radius: 50%;
        }
    </style>
</head>
<body>
<div id="app">
    <div class="wrap" >
        <!--在根组件中用子组件,-->
        <!--:pict就是用来标志,在子组件中接收的是哪一个值,他就是把父级组件中对应的每一次循环的list的dic传到子集组件-->
        <mytag V-for="dic in list" :pict="dic"></mytag>
    </div>
</div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
    // 定义一个全局的数组对象
    let list = [
        {title:'图片一号',img:'img/1.jpg'},
        {title:'图片二号',img:'img/2.jpg'},
        {title:'图片三号',img:'img/3.jpg'},
        {title:'图片四号',img:'img/4.jpg'},
        {title:'图片一号',img:'img/1.jpg'},
        {title:'图片二号',img:'img/2.jpg'},
        {title:'图片三号',img:'img/3.jpg'},
        {title:'图片四号',img:'img/4.jpg'},

    ];

    //自定义的子组件
    let mytag = {
        // prop 它就是利用反射的机制来接收父级组件传递过来的pict的值,通过字符串的形式
        props:['pict'],

        // 子组件在内部用了两个自己没有定义的数据属性(pict.img/pict.title)
        template:`
            <div class="box">
                <img :src="pict.img" alt="">
                <p>{{pict.title}}</p>
                <p @click="clickEvent" style="cursor:pointer">点击:{{count}}次</p>
            </div>
        `,

        //这是子组件的count数据的申明
        // 固定语法:如果不是从父级组件传递来的数据,那就需要这样写
        data(){
            return{
                //给count的初始值为0
                count:0
            }
        },
        //这是子组件中的事件发生触发用的
        methods:{
            clickEvent(){
                this.count++
            }
        }
    };

    // 这里是根组件
    new Vue({
        el:'#app',
        data:{
            // 将上面全局的数组数据加载到Vue实例中
            list,
        },
        components:{
            mytag,
        }
    })
</script>
</html>

2. 子组件向父组件传递数据

通过发送事件请求的方式进行数据传递

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <h2>{{msg}}</h2>
    <!--这里的send_msg 就是我们自己注册的一个事件,当遇到子集组件中的this.emit的时候,会自动触发-->
    <!--同时也需要在父级组件中去注册这个事件,methods中-->
    <mytitle @send_msg="changeMsg"></mytitle>
</div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
    // 定义一个子组件
    let mytitle={

        // 给子组件的input标签设置v-model 监听事件
        template:`
            <input type="text" v-model="msg">
        `,
        // 先给msg一个初始值
        data(){
            return {
                msg:''
            }
        },
        // v-model的监听事件
        watch:{
            // 也就是我们设设置监听的msg变量
            msg(){
                // 当msg的值开始改变时,触发这个函数方法
                // this.$emit 就是用来触发挂载点根模板的事件的,然后顺便把msg的值传过去
                this.$emit('send_msg',this.msg)
            }
        }

    };
    new Vue({
        el:'#app',
        data:{
            msg:'我正在等待接收子组件的值'
        },
        components:{
            mytitle,
        },

        // 挂载点模板中的事件,用来接收自己模板的传送的数据的
        methods:{
            changeMsg(msg){
                if (msg){
                    this.msg = msg
                }
            }
        }
    })
</script>
</html>

2. 平行组件之间传递数据

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>平行组件传值</title>
</head>
<body>
<div id="app">
    <app1></app1>
    <app2></app2>
</div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
    // 首先实例化一个公共得全局得Vue对象
    let Bus = new Vue();
    
    // 这里是第一个组件
    Vue.component('app1', {
        data() {
            return {
                msg: '我是平行组件的数据'
            }
        },
		
        // 这个是第一个组件模板,他有一个点击事件,点击触发一个事件,讲自己的数据传递给与自己统计的组件
        template:`<button @click="clickEvent">传递</button>`,
        methods:{
            clickEvent(){
                
                // 这时候就用到了在上面定义的一个全局的Vue的Bus对象
                // Bus.$emit('触发的一个事件名',传递过去的数据参数)
                Bus.$emit('textmsg',this.msg)
            }
        }
    });
	
    // 这是第二个组件
    Vue.component('app2', {
        data() {
            return {
                text:'',
            }
        },
        template:`<p">{{text}}</p>`,

        // created() 这个方法是在当前组件呗创建的时候会自动调用
        // 所以在创建之前,我们可以对该组件的数据进行处理
        created(){
            // 这里又调用了上面定义的全局的Bus对象的绑定的那个方法
            // .$on('自己组件的一个方法,当其他组件向这个方法传数据的时候,会调用,')
            // 并接收传过来的数据
            Bus.$on('textmsg',function (val) {
                console.log(val);
            })
        }
    });

    new Vue({
        el: '#app',
    })

</script>
</html>

六、slot内容分发

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>slot内容分发</title>
</head>
<body>
<div id="app">
    <!--<mytag>我要替换</mytag>-->
    <!--<mytag>我要替换</mytag>-->
    <mytag>我要替换</mytag>
</div>
</body>
<script src="Vue_js/vue.js"></script>
<script>
    let mytag = {

        // slot就是说明p标签的文本内容可以在使用这个子组件的时候被替换
        template:`
            <!--<p>我是不可以被其他值替换掉的</p>-->
            <p><slot>jfgj</slot></p>
        `
    };
    new Vue({
        el: '#app',

        components:{
            mytag,
        }
    })
</script>
</html>

七、组件的过滤器

过滤器就是给一个值进行额外的操作

1. 全局过滤器

Vue.filter('过滤器名',function([使用过滤器的数据变量]参数1,参数2,参数3){
    一系列操作
    返回·····
})


// 全局过滤器也可以写很多个

2. 局部过滤器

// 过滤器的参数,第一个val是使用这个过滤器的数据变量,后面所有的参数都是在时候过滤器的时候,手动传过来的
// 同样可以有多个过滤器的方法
        filters: {
            stringdate([使用过滤器的数据变量]参数1,参数2,参数3) {
                一系列操作
                返回······
            }
        }

3. 案例

以下是一个通过过滤器处理时间的案例

在这里我们会介绍一个moment.js的使用,这个moment.js他是一个专门用来处理时间格式的

详情http://momentjs.cn/,点击直接进行以下操作

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>全局过滤器</title>
</head>
<body>
<div id="app">
    <mytag></mytag>
</div>
</body>
<script src="Vue_js/vue.js"></script>

//这里我是把这个js文件和Vue.js的文件放在一个文件夹中的,引入方式就是这样
<script src="Vue_js/moment.js"></script>
<script>
    // 组件的全局过滤器
    Vue.filter('string',function (time,str) {
            // moment是一个处理事件的库
            return moment(time).format(str)
    });

    let mytag = {
        data() {
            return {
                time: new Date(),
                ctime:new Date(),
            }
        },
        template: `
            <div>
                <p>hello World</p>

                // 这里使用的是全局过滤器
                <p>{{time|string('YYYY-MM')}}</p>

                // 这里使用的是局部过滤器
                <p>{{ctime|stringdate('YYYY-MM-DD')}}</p>
            </div>
        `,

        // 这是局部过滤器,里面可以写多个过滤器
        // 过滤器的参数,第一个val是使用这个过滤器的数据变量,后面所有的参数都是在时候过滤器的时候,手动传过来的
        filters: {
            stringdate(ctime, str) {
                return moment(ctime).format(str)
            }
        }

    };

    new Vue({
        el: "#app",

        components: {
            mytag,
        }
    })
</script>
</html>
posted @ 2019-11-23 18:42  Cecilia陈  阅读(128)  评论(0编辑  收藏  举报