• Vue组件


    Vue组件

    • 组件:由html、css、js三部分组成的独立单位,可以类似于变量,重复使用

    • 组件其实就是vue实例(对象),一个组件就是一个vue实例(对象)

    • new Vue() 产生的也是实例(对象),所以也是组件,称之为根组件

      一个页面建议只出现一个根组件(项目开发模式下,一个项目建议只出现一个根组件)

    • 组件的html页面结构由 template 实例成员提供

      template提供的html结构是用来构建虚拟DOM,真实DOM最终会被虚拟DOM替换

      根组件一般不通过template,就由挂载点来提供构建虚拟DOM的页面结构,根组件如果提供了template,还需要设置挂载点作为替换占位。

      template模板有且只有一个根标签。

    根组件

    通过new Vue()创建的实例就是根组件(实例与组件一一对应,一个实例就是一个组件)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>根组件</title>
    </head>
    <body>
    <div id="app">
        <h1>{{ msg }}</h1>
    </div>
    <script src="js/vue.js"></script>
    <script>
        // 通过new Vue()创建的实例就是根组件(实例与组件一一对应,一个实例就是一个组件)
        // 每个组件均拥有模板,template
        let app = new Vue({
            // 根组件的模板就是挂载点
            el: '#app',
            data: {
                msg: '根组件'
            },
            // 模板:由""包裹的html代码块,出现在组件的内部,赋值给组件的$template变量
            // 显示书写模板,就会替换挂载点,但根组件必须拥有挂载点
            template: "<div>显示模板</div>"
        });
        // app.$template
    </script>
    
    </body>
    </html>
    

    子组件

    在根组件template中加载的组件,称之为根组件的子组件

    如何定义子组件

    组件就是一个普通对象,内部采用vue语法结构,被vue注册解释后,就会成为vue组件。eg:

    <!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',
            components: {
                // 'my-tag': myTag,
                // myTag: myTag,
                myTag,
            }
        })
    </script>
    </html>
    

    子组件数据局部化

    // 子组件
    let tag = {
        template: `...`,
        // 能被复用的组件(除了根组件),数据都要做局部化处理,因为复用组件后,组件的数据是相互独立的
        // data的值为绑定的方法的返回值,返回值是存放数据的字典
        data() {
            return {
               	// 数据...
            }
        }
    }
    // 在哪个组件模板中出现的属性变量和方法变量,都由当前所属组件自己提供
    

    eg:

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            .wrap {
                 calc(200px * 4 + 80px);
                margin: 0 auto;
                user-select: none;
            }
            .box {
                 200px;
                height: 260px;
                /*border: 1px solid black;*/
                background-color: rgba(10, 200, 30, 0.5);
                border-radius: 10px;
                float: left;
                margin: 10px;
            }
            .box img {
                 100%;
                /*height: 200px;*/
                border-radius: 50%;
            }
            .box p {
                text-align: center;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <div class="wrap">
                <tag></tag>
                <tag></tag>
                <tag></tag>
                <tag></tag>
            </div>
        </div>
    </body>
    <script src="js/vue.js"></script>
    <script>
        let titleTag = {
            template: `
            <p>
                <b>
                    这是一种纯二哈
                </b>
            </p>
            `,
        };
    
        let tag = {
            template: `
            <div class="box">
                <img src="img/001.jpg" alt="">
                <title-tag />
                <p @click="fn">
                    锤它:<b>{{ num }}下</b>
                </p>
            </div>
            `,
            // 能被复用的组件(除了根组件),数据都要做局部化处理,因为复用组件后,组件的数据是相互独立的
            // data的值为绑定的方法的返回值,返回值是存放数据的字典
            data () {
                return {
                    num: 0
                }
            },
            methods: {
                fn() {
                    this.num ++
                }
            },
            components: {
                titleTag,
            }
        };
    
    	new Vue({
    		el: '#app',
            components: {
    		    tag,
            }
    	});
    
    </script>
    </html>
    

    父组件传递数据给 子组件

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

    • 数据在父组件中产生
    • 在父组件中渲染子组件,子组件绑定自定义属性,附上父组件中的数据
    • 子组件自定义属性在子组件的props成员中进行声明(采用字符串反射机制)
    • 在子组件内部,就可以用props声明的属性(直接作为变量)来使用父组件中的数据
    <div id="app">
        <!-- 在父组件汇总使用子组件-->
    	<tag :sub_msg="msg" />
    </div>
        
    <script>
        // 子组件
    let tag = {
        // 在组件内部就可以通过设置的自定义属性sub_msg,拿到外部选择子组件提供给属性的值
        props: ['sub_msg'],
        template: `<div>{{ sub_msg }}</div>`,
    }
    
    new Vue({
        el: '#app',
        // 注册子组件
        components: {
            tag,
        },
        data: {
            msg: '父级数据'
        }
    })
    </script>  
    
    

    eg:

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>父传子</title>
        <style>
            .wrap {
                 calc(200px * 4 + 80px);
                margin: 0 auto;
                user-select: none;
            }
            .box {
                 200px;
                height: 260px;
                /*border: 1px solid black;*/
                background-color: rgba(10, 200, 30, 0.5);
                border-radius: 10px;
                float: left;
                margin: 10px;
            }
            .box img {
                /* 100%;*/
                height: 160px;
                border-radius: 50%;
                margin: 0 auto;
                display: block;
            }
            .box p {
                text-align: center;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <div class="wrap">
                <tag v-for="dog in dogs" v-bind:dog="dog" :a="1" :b="2" />
            </div>
        </div>
    </body>
    <script src="js/vue.js"></script>
    <script>
        let dogs = [
            { title: '二哈1号', img: 'img/1.jpg', },
            { title: '二哈2号', img: 'img/2.jpg', },
            { title: '二哈3号', img: 'img/3.jpg', },
            { title: '二哈4号', img: 'img/4.jpg', },
        ];
    
        let tag = {
            // 在组件内部就可以通过设置的自定义属性,拿到外部选择子组件提供给属性的值
            props: ['dog', 'a', 'b', 'z'],
            template: `
            <div class="box">
                <img :src="dog.img" alt="">
                <p>
                    <b>
                        {{ dog.title }}
                    </b>
                </p>
                <p @click="fn">
                    锤它:<b>{{ num }}下</b>
                </p>
            </div>
            `,
            data () {
                return {
                    num: 0,
    
                }
            },
            methods: {
                fn() {
                    this.num ++
                }
            },
        };
    
    	new Vue({
    		el: '#app',
            data: {
    		    dogs,
            },
            components: {
    		    tag,
            }
    	});
    
    </script>
    </html>
    

    子组件传递数据给父组件

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

    <div id="app">
        <h1> {{ title }} </h1>
        <!-- 组件标签不能添加系统事件,只能添加自定义事件,自定义事件在组件内部通过$emit主动触发 -->
        <tag @self_action="changeTitle"/>
    </div>
        
    <script>
    	let tag = {
            template: `
            <div>
                <input v-model="sub_title" />
            </div>
            `,
            data() {
                return {
                    sub_title: ''
                }
            },
            watch: {
                // 监听sub_title属性,值一改变就会触发
                sub_title() {
                    // 将sub_title与父级的title建立关联
                    // 激活(触发)self_action自定义事件
                    this.$emit('self_action', this.sub_title)
                }
            }
        };
    
        new Vue({
            el: '#app',
            components: {
                tag,
            },
            data: {
                title: '父级初始标题'
            },
            methods: {
                changeTitle(sub_title) {
                    this.title = sub_title ? sub_title : '父级初始标题';
                }
            }
        })
    </script>  
    

    eg:

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>子传父</title>
        <style>
            ul {
                list-style: none;
            }
            .d-btn {
                font-size: 12px;
                 15px;
                display: inline-block;
            }
            .d-btn:hover {
                color: red;
                cursor: pointer;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <input type="text" v-model="msg">
            <button @click="send_comment">留言</button>
            <ul>
                <tag v-for="(v, i) in comments" :msg="v" :index="i" @f1="deleteMsg"/>
            </ul>
        </div>
    </body>
    <script src="js/vue.js"></script>
    <script>
        let tag = {
            props: ['msg', 'index'],
            template: `
            <li>
                <i class="d-btn" @click="fn">x</i>
                <b>{{ msg }}</b>
            </li>
            `,
            methods: {
                fn () {
                    // 点击子集,要告诉父级删除第几条数据,因为comments在父级中
                    // 需要通知父级,f1是事件,事件才能绑定方法,绑定父级的方法deleteMsg,才能接收到传过去的数据
                    this.$emit('f1', this.index);
                }
            }
        };
    
        new Vue({
            el: '#app',
            data: {
                msg: '',
                comments: localStorage.comments ? JSON.parse(localStorage.comments) : [],
            },
            components: {
                tag,
            },
            methods: {
                send_comment() {
                    if (this.msg) {
                        this.comments.push(this.msg);
                        this.msg = '';
                        localStorage.comments = JSON.stringify(this.comments);
                    }
                },
                deleteMsg(index) {
                    this.comments.splice(index, 1);
                    localStorage.comments = JSON.stringify(this.comments);
                }
            }
        })
    </script>
    <script>
        // localStorage,sessionStorage不能直接存储数组和对象,需要序列化为json
        localStorage.arr = JSON.stringify([1, 2, 3]);  // 前端操作json序列化
        let res = JSON.parse(localStorage.arr);        // 前端解析json数据
        console.log(res, res[2]);
    </script>
    </html>
    

    综合应用练习

    有以下广告数据(实际数据命名可以略做调整)
    ad_data = {
    tv: [
    {img: 'img/tv/001.png', title: 'tv1'},
    {img: 'img/tv/002.png', title: 'tv2'},
    {img: 'img/tv/003.png', title: 'tv3'},
    {img: 'img/tv/004.png', title: 'tv4'},
    ],
    phone: [
    {img: 'img/phone/001.png', title: 'phone1'},
    {img: 'img/phone/002.png', title: 'phone2'},
    {img: 'img/phone/003.png', title: 'phone3'},
    {img: 'img/phone/004.png', title: 'phone4'},
    ]
    }

    i) 有两个大标题,电视和手机,点击对应的标题,渲染对应的数据
    ii) 一个字典作为一个显示单位,定义一个子组件进行渲染(涉及父子组件传参)

    在上一题基础上,页面最下方有一个 h2 标签,用来渲染用户当前选择的广告(点击哪个广告就是选中哪个广告)
    i)当没有点击任何广告,h2 标签显示:未选中任何广告
    ii)当点击其中一个广告,如tv1,h2 标签显示:tv1被选中

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            .wrap {
                 calc(200px * 4 + 80px);
                margin: 0 auto;
                user-select: none;
            }
    
            .box {
                 200px;
                height: 260px;
                /*border: 1px solid black;*/
                background-color: rgba(10, 200, 30, 0.5);
                border-radius: 10px;
                float: left;
                margin: 10px;
                overflow: hidden;
            }
    
            .box img {
                /* 100%;*/
                height: 160px;
                /*border-radius: 50%;*/
                margin: 0 auto;
                display: block;
            }
    
            .box p {
                text-align: center;
            }
            .action{
                background-color: pink;
            }
        </style>
    </head>
    <body>
    <div id="app">
        <div class="wrap">
            <p>
                <button :class="{action: role === 'tv'}" @click="show('tv')">点击展示电视</button>
                <button :class="{action: role === 'phone'}" @click="show('phone')">点击展示手机</button>
            </p>
            <div v-if="role === 'tv'">
                <tag v-for="(tv, i) in tv" :data="tv" :index="i" @f1="choice"></tag>
            </div>
            <div v-else-if="role === 'phone'">
                <tag v-for="(phone, i) in phone" :data="phone" :index="i" @f1="choice"></tag>
            </div>
        </div>
        <div>
            <h2>{{ msg }}</h2>
        </div>
    </div>
    </body>
    <script src="js/vue.js"></script>
    <script>
        let tv = [
            {img: 'img/tv/001.jpg', title: 'tv1'},
            {img: 'img/tv/002.jpg', title: 'tv2'},
            {img: 'img/tv/003.jpg', title: 'tv3'},
            {img: 'img/tv/004.jpg', title: 'tv4'},
        ];
    
        let phone = [
            {img: 'img/phone/001.jpg', title: 'phone1'},
            {img: 'img/phone/002.jpg', title: 'phone2'},
            {img: 'img/phone/003.jpg', title: 'phone3'},
            {img: 'img/phone/004.jpg', title: 'phone4'},
        ];
    
        let tag = {
            props: ['data', 'index'],
            template: `
            <div class="box" @click="fn">
                <p>
                    <b>{{ data.title }}</b>
                </p>
                <img :src="data.img" alt="">
            </div>
            `,
            methods: {
                fn(){
                    this.$emit('f1', this.index);
                }
            }
        };
    
        new Vue({
            el: '#app',
            data: {
                tv,
                phone,
                role: 'tv',
                msg: '未选中任何广告',
            },
            components: {
                tag,
            },
            methods: {
                show(role) {
                    this.role = role;
                },
                choice(index) {
                    // console.log(111);
                    let obj = this.role==='tv'? this.tv : this.phone;
                    this.msg = obj ? obj[index]['title'] +'被选中' : this.msg;
                },
            }
        });
    </script>
    </html>
    
  • 相关阅读:
    CART回归树基本原理(具体例子)
    Leetcode 236. 二叉树的最近公共祖先 & 235. 二叉搜索树的最近公共祖先(Python3)
    c和c++的区别
    最小编辑距离python
    判断单链表是否有环,并找出环的入口python
    关键词提取算法-TextRank
    leetcode406 ,131,1091 python
    id3算法python实现
    Relu激活函数的优点
    从 AllocateMessageQueueConsistentHash 看一致性哈希
  • 原文地址:https://www.cnblogs.com/zhuangyl23/p/11861965.html
Copyright © 2020-2023  润新知