Vue组件 知识点总结


一、组件知识点

1. 组件的注册


<body>
    <div id="app">
        <hello></hello>
        <world></world>
    </div>

    <div id="root">
        <hello></hello>
        <world></world>//局部注册的组件world显示不出来
    </div>

    <script src="/vue.js"></script>

    <script>
        //全局注册组件(创建组件,要在new Vue之前)
        Vue.component('hello', {
            //组件的模板(组件要显示的标签)
            template: `
            <div>
                <h2>Hello</h2>
             </div>
          `
        });

        //局部注册组件
        new Vue({
            el: '#app',
            components: {
                'world': {
                    template: `<h3>world</h3>`
                }
            }
        })
        new Vue({
            el: '#root'
        })
    </script>

</body>

2.组件中的属性

<body>
    <div id="app">
        <my-component></my-component>
    </div>
    <script src="/vue.js"></script>
    <script>
    //创建全局组件:
        Vue.component('my-component',{
            template:`
                <div>
                    <h1>{{msg}}</h1>
                    <h1>{{newMsg}}</h1>
                </div>
            `,
            //和之前一样data,computed等都能用
            data(){
                return{
                    msg:'你好呀'
                }
            },
            computed:{
                newMsg(){
                    return '我不好'
                }
            }
        });
        //为什么组件中data()只能用函数返回的形式:
        //因为组件要多次使用,以保证每个组件用的data独立
        //使得每个实例可以维护一份被返回对象的独立的拷贝(官方的话)
        // const a = data();
        // const b = data();

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

二,自定义属性

1.props的基本使用

Vue中为组件提供了一个props 的属性,在组件上注册的一些自定义属性,通过props,使得父组件向子组件传值。

注意:当父组件向子组件传递数据时,除了字符串,其他所有数据类型都需要通过v-bind 来进行传递。

<body>
    <div id="app">
        <father></father>
    </div>
    <script src="/vue.js"></script>
//父子组件的前提是有嵌套关系。 注意:局部组件不能嵌套到全局组件中。 
//1.父组件传值:父组件中,给子组件设置属性,进行传值。
    <script>
        Vue.component('father', {
            template: `
                 <div>
                    <child name="zhangsan" age="20"></child>
                 </div>
            `
        })
        
//2.子组件接收值:通过props属性,在数组或对象中设置对应的属性名,来接收父组件传递的数据。
        Vue.component('child', {
            props:['name','age'],
            template: `
                <span>{{name}} {{age}}</span>
            `
        })
        new Vue({
            el: '#app'
        })
    </script>
</body>

2. props的验证

props 可以通过设置成对象的形式,来进行props的验证。

<body>
    <div id="app">
        <father></father>
        <hr>
        <hr>
        <child></child>
    </div>
    
    <script src="/vue.js"></script>
    <script>
        Vue.component('father', {
            template: `
                 <div>
                    <h1>father</h1>
                    <span>{{msg}}</span>
                    <child :name="msg" age='20' gender="女"></child>
                 </div>
            `,
            data() {
                return {
                        msg:'father msg'
                }
            }
        })

        Vue.component('child', {
            props:{
                name:String,            //name接收的数据类型为String
                age:[Number,String],    //age接收的数据类型为Number或String
                gender:{
                    type:String,       //gender接收的数据类型为String
                    default:'男'       //当没有接收到gender属性值时,采用default的默认值'男'
                },
                friends:{
                    type:Object,
                    default:()=>({})   //当默认值为数组或对象时,要以函数返回值的形式来设置默认值
                }
            },
            template: `
            <div>
                <h2>child</h2>
                <span>{{name}} {{age}} {{gender}}</span>
            </div>
            `
        })
        new Vue({
            el: '#app'
        })
    </script>
</body>

在这里插入图片描述

三,自定义事件

1.基础语法

  1. 在父组件的 methods属性中定义事件的方法,然后在调用子组件时,通过@自定义名称=方法名,来向子组件传递自定义事件。
  2. 子组件通过@事件类型="$emit('自定义事件名称')”来触发父组件传递的自定义事件。
<body>
    <div id="app">
        <father></father>
    </div>
    
    <script src="/vue.js"></script>
    <script>
        Vue.component('father',{
            template:`
                <div>
                    <child @sayHello="sayHello"></child> 
                </div>            
            `,
            methods: {
                sayHello(){
                    console.log('hello')
                }
            }
        })

          Vue.component('child',{
            template:`
                <div>
                    <h1 @click="$emit('sayHello')">child</h1>
                </div>            
            `
        })
        new Vue({
           el:'#app'
        })
    </script>
</body>

2. 自定义事件的使用场景

2.1 子组件修改父组件的数据

在父组件中定义一个修改父组件数据的方法,然后通过自定义事件将该方法传递给子组件,让子组件来触发该方法。

<body>
    <div id="app">
        <father></father>
    </div>

    <script src="/vue.js"></script>
    <script>
        Vue.component('father',{
            template:`
                <div>
                    <h1>{{num}}</h1>
                    <child @add="add"></child>
                </div>            
            `,
            data() {
                return {
                    num:100
                }
            },
            methods: {
                add(){
                    this.num++
                }
            }
        })

          Vue.component('child',{
            template:`
                <div>
                    <button @click="$emit('add')">+1</button>
                </div>            
            `
        })
        new Vue({
           el:'#app'
        })
    </script>
</body>
2.2 子组件传值给父组件

当子组件想要将数据传递给父组件时,通过调用父组件的方法,来进行数据的传递。

<body>
    <div id="app">
        <father></father>
    </div>

    <script src="/vue.js"></script>
    <script>
        Vue.component('father',{
            template:`
                <div>
                    <h1>{{num}}</h1>
                    <child @add="add"></child>
                </div>            
            `,
            data() {
                return {
                    num:100
                }
            },
            //函数可以接收参数
            methods: {
                add(newNum1,newNum2){
                    this.num += newNum1+newNum2;
                }
            }
        })
        
   //$emit()的第二个参数,用来向父组件传递数据
          Vue.component('child',{
            template:`
                <div>
                    <button @click="$emit('add',5,10)">+15</button>
                </div>            
            `
        })
        new Vue({
           el:'#app'
        })
    </script>
</body>

四,组件案例

1. 组件版计数器

需求:加一减一,失焦变成123
在这里插入图片描述

<body>
    <div id="app">
    //父组件counter中包含了两个子组件
        <counter></counter>
    </div>
    <script src="/vue.js"></script>
    <script>
        //注意:组件名需要加引号
        Vue.component('counter', {
            template: `
            <div>
                             //自定义属性
                <show-count :count="count"></show-count> 
                             //自定义事件
                <set-count @increment="increment" @decrement="decrement" @inputCount="inputCount"></set-count>
            </div>
            `,
            //show和set都要用数据,因此数据放在父组件身上
            data() {
                return {
                    count: ''
                }
            },
            methods: {
                // 子组件修改父组件的数据
                increment() {
                    this.count++;
                },
                decrement() {
                    this.count--;
                },
                //子组件传值给父组件
                inputCount(newCount) {
                    this.count = newCount
                }
            }
        })

        //父传子
        Vue.component('show-count', {
            props: {
                count: {
                    type: [Number, String],
                    default: 0
                }
            },
            template: `
                <h1>计数器:{{count}}</h1>
            `
        })

        //子传父
        //@blur是当元素失去焦点时所触发的事件 
        Vue.component('set-count', {
            template: `
                <div>
                    <button @click="$emit('increment')">+1</button>
                    <button @click="$emit('decrement')">-1</button>
                                     //给input加了ref属性
                    <input type="text" ref="newCount" @blur="inputCount">              
                </div>
            `,
            methods: {
                inputCount() {
                    const value = this.$refs.newCount.value;
                    this.$emit('inputCount', value);
                    this.$refs.newCount.value = '';
                }
            },
        })

        new Vue({
            el: '#app',

        })
    </script>
</body>

假设:在vue 中,需要操作DOM了,需要拿到页面上某个DOM元素的引用,此时怎么办?
答:ref引用,ref用来辅助开发者在不依赖于jQuery的情况下,获取DOM元素或组件的引用。
注意:每个vue的组件实例上,都包含一个 $refs对象,里面存储着对应的DOM元素或组件的引用。默认情况下,组件的 $refs指向一个空对象。

2. 组件版todolist

需求:一个父组件,三个子组件。在这里插入图片描述

 <style>
        .done {
            color: red;
            text-decoration: line-through;
        }
        .btnsName>*{
            margin-right: 10px;
        }
    </style>
    
<body>
    <div id="app">
        <todolist></todolist>
    </div>
    <script src="/vue.js"></script>
    <script>
    //父组件:
        Vue.component('todolist', {
            template: `
            <div>
                <addTo @addTodo="addTodo"></addTo>
                <list :listData="filterListData" @doneToggle="doneToggle"></list>
                <btns :current="current" @currentToggle="currentToggle"
                    :total="listData.length" :doneTotal="doneTotal"></btns>
            </div>
            `,
            data() {
                return {
                    listData: [
                        { text: 'HTML', done: false },
                        { text: 'CSS', done: true },
                        { text: 'JS', done: false },
                    ],
                    current:'ALL'
                }
            },
            computed:{
                filterListData(){
                    switch(this.current){
                        case'DONE':return this.listData.filter(item=>item.done);
                        case'ACTIVE':return this.listData.filter(item=>!item.done);
                        default:return this.listData;
                    }
                },
                doneTotal(){
                    return this.listData.filter(item=>item.done).length;
                }
            },
            methods: {
                addTodo(text) {
                    this.listData.push({
                        text,
                        done: false
                    });
                },
                //单向数据流,不能修改props,不能在子组件list中用@click="item.done=!item.done"切换样式。
                //因此在父组件中根据子组件传过来的下标index修改。
                doneToggle(index) {
                    this.listData[index].done = !this.listData[index].done
                },
                currentToggle(current){
                    this.current = current;
                }
            }
        })

        Vue.component('addTo', {
            data() {
                return {
                    text: ''
                }
            },
            template: `
            <div>
                <input type="text" v-model.lazy="text">
                <button @click="addTodo">addTo</button>
            </div>
            `,
            methods: {
                addTodo() {
                    this.$emit('addTodo', this.text),
                        this.text = ''
                }
            }
        })

        Vue.component('list', {
            props: {
                listData: {
                    type: Array,
                    default: () => []
                }
            },
            template: `
            <div>
                <ul>
                    <li v-for="(item,index) in listData" :key="index"
                       @click="$emit('doneToggle',index)"
                       :class="{done:item.done}">
                       {{item.text}}
                    </li>
                </ul>
            </div>
            `,
        })

        Vue.component('btns', {
            props:['current','total','doneTotal'],
            data(){
                return{
                    btnsName:['ALL','DONE','ACTIVE'],
                }
            },
            template: `
            <div class="btnsName">
                <template v-for="item in btnsName">
                    <span v-if="item == current" :key="item">{{item}}</span>
                    <a href="" v-else :key="item" @click.prevent="$emit('currentToggle',item)">{{item}}</a>
                </template>
                <span>{{doneTotal}}/{{total}}</span>
            </div>
            `
        })
        
        new Vue({
            el: '#app'
        })
    </script>
</body>

五,生命周期

在这里插入图片描述
例子:

<body>
    <div id="app">
        <h1>{{msg}}</h1>
        <button @click="msg='我不好'">按钮</button>
        <button @click="$destroy()">销毁</button>
    </div>
    <script src="/vue.js"></script>
    
    //created,mounted:页面初始化时向服务端发起请求。
    <script>
        new Vue({
            el: "#app",
            data() {
                return {
                    msg: "你好"
                }
            },
            beforeCreate() {
                console.log('创建前');
            },
            created() {
                console.log('创建完成');
            },
            beforeMount() {
                console.log('挂载前');
            },
            mounted() {
                console.log('挂载完成');
            },
            beforeUpdate() {
                console.log('数据更新前');
            },
            updated() {
                console.log('数据更新完成');
            },
            beforeDestroy() {
                console.log('销毁前');
            },
            destroyed() {
                console.log('销毁完成');
            }
        })
    </script>
</body>

六,插槽

1.基本用法

//知识点:
1.插槽的内容:从组件外部向组件内部的插槽添加内容。
2.插槽的默认值:当没有给插槽传递数据时,默认插槽内容为空,给插槽手动设置默认值,页面就显示插槽的默认值。
3.具名插槽:一个组件中,有多个插槽时,可以通过name属性给插槽设置名字。

<body>
    <div id="app">
        <cpn>
        //具名插槽的v-slot只能写在template中
            <template v-slot:header>
               <h3>插槽的内容</h3>
            </template>

            <template v-slot:footer>
		//没有给插槽传递内容,显示插槽的默认值
             </template>
        </cpn>
    </div>
    <script src="/vue.js"></script>
    <script>
        Vue.component('cpn', {
            template:`
                <div>
                   <slot name="header"></slot>
                   <h3>文章一</h3>
                   <h3>文章二</h3>
                   <h3>文章三</h3>
                   <slot name="footer">插槽的默认值</slot>
                </div>
            `
        })
        new Vue({
            el: '#app'
        })
    </script>
</body>

2. 作用域插槽

当插槽中渲染的数据由插槽所在的子组件提供,而插槽显示的标签由父组件提供,这种情况下就需要用到作用域插槽。

//用无序列表和有序列表渲染学生列表students
<body>
    <div id="app">
        <father></father>
    </div>
    <script src="/vue.js"></script>
    <script>
        Vue.component('father', {
            template:`
                <div>
                    <child v-slot="slotProps">
                        <ul>
                            <li v-for="item in slotProps.students">{{item}}</li>
                        </ul>
                    </child>
                    <child v-slot="slotProps">
                        <ol>
                            <li v-for="item in slotProps.students">{{item}}</li>
                        </ol>
                    </child>
                </div>
            `
        });

        Vue.component('child', {
            data(){
                return{
                    students:['张三','李四','王五']
                }
            },
            template:`
            <div>
                <h3>学生列表</h3>
                <slot :students="students"></slot>
            </div>    
            `
        })
        
        new Vue({
            el: '#app'
        })
    </script>
</body>

七,动态组件

在这里插入图片描述

案例:

<body>
    <div id="app">
        <tabs></tabs>
    </div>
    <script src="/vue.js"></script>
    
    <script>
        Vue.component('tabs',{
            data() {
                return {
                    current:'Home'
                }
            },
     //<keep-alive>标签:切换组件不会重新渲染
            template:`
            <div>
                <div>
                    <button @click="current = 'Home'">Home</button>
                    <button @click="current = 'About'">About</button>
                    <button @click="current = 'Posts'">Posts</button>
                </div>
                <div>
                    <keep-alive> 
                        <component :is="current"></component>  
                    </keep-alive>
                </div>
            </div>
            `
        })

        Vue.component('Home',{
            template:`
                <h1>Home的组件内容</h1>
            `
        })
        Vue.component('About',{
            template:`
               <div>
                   <h1>About的组件内容</h1>
                   <input type="text">
               </div>
            `
        })
        Vue.component('Posts',{
            template:`
                <h1>Posts的组件内容</h1>
            `
        })
        new Vue({
           el:'#app'
        })
    </script>
</body>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值