vue组件化(第四天)

简介: vue组件化(第四天)
vue两大核心

1.数据驱动界面

2.组件化

什么是组件化?

1.组件化就是把一个大界面拆分成一个个小组件,相同结构的组件可以进行复用,每一个小界面就是一个组件

组件化有利于提高复用性,简化Vue实例化代码

全局组件

全局组件在任何一个Vue实例控制区域都能使用

Vue中如何创建组件?
  1. 创建组件构造器
  2. 注册已经创建好的组件
  3. 使用注册号的组件
    [注意]:创建组件构造器的时候只能有一个根元素,因此我们通常用div直接把我们想包含的元素包起来

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
<!--    3.使用注册号的组件-->
    <shanjialan></shanjialan>
</div>
<script>
    // 1. 创建组件构造器
    let component=Vue.extend({
        template:`
            <div>
                <p>shanjialan111</p>
                <p>shanjialan222</p>
            </div>
    `});
    // 2.注册已经创建好的组件
    Vue.component("shanjialan",component);
    let vue=new Vue({
        el:"#app",
        data:{
            name:"单佳兰"
        },
        methods:{
            myFn(){
                alert("sjl");
            }
        }
    });
</script>
</body>
</html>

26.png

image.png

vue创建组件的简写方法

// 注册组件,传入一个扩展过的构造器
Vue.component('my-component', Vue.extend({ /* ... */ }))
// 注册组件,传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-component', { /* ... */ })
// 获取注册的组件 (始终返回构造器)
var MyComponent = Vue.component('my-component')

2. 注册组件,传过来一个组件构造器

Vue.component("shanjialan",Vue.extend({
        template:`<a href="#">link</a>`
    }))

3.省略组件构造器Vue-extend,也会直接调用

Vue.component("bcd",{
        template:`<a href="#">zhiboyu</a>`
    })

总结:上面三种方法定义组件构造器html代码都没有提示,效率比较低,因此我们要想其他办法来避免这个问题——使用script标签添加id属性,并且将type设为text/html即可,再通过id作为构造器的第二个参数传递给vue-component,代码如下:

<script id="info" type="text/html">
    <a href="#">单佳兰</a>
</script>

但是这种方法其实是不大科学的,明明是HTML,为什么要用script进行封装?于是有了第五种方法,使用<template>加上id属性来封装,这个template就相当于<script id="#" type="text/html>

<template id="shanshun">
    <a>shuanshun</a>
</template>

Vue.component("shanshun",{
        template:"#shanshun"
    })

局部组件

局部组件的使用——在vue实例中添加components以键值对的方式定义,里面的格式和全局组件一样

<template id="shanshun">
    <a>shuanshun</a>
</template>

let vue=new Vue(
components:{
  "shanshun":{
        template:"#shanshun"
    })
}

data和method

1.自定义组件中的data和methods

Vue实例相当于一个大的组件,其中有data和methods属性,相同地,自定义组件相当于一个小的组件,因此也有data和methods属性,但是在自定义组件中data不大一样,在自定义组件中使用data必须赋值一个函数,通过函数返回值来定义数据

Vue.component("shanshun", {
        template: "#shanshun",
        data: function() {
            return{
                name: "shanshun22"
              }
        },
    methods:{
         myApp(){alert('shanjialan');}
    })

为什么自定义组件的data不用对象返回,而是通过函数返回的,因为通过对象定义,那么多个组件就会共用一份数据,就会导致数据混乱,将这个方法返回的数据和当前创建的组件绑定在一起,就避免了数据混乱的问题

image.png

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
    <ab></ab>
    <ab></ab>
    <ab></ab>
</div>
<template id="addnum">
    <div>
        <button @click="add">按钮</button>
        <p>{{number}}</p>
    </div>
</template>
<script>
    //自定义组件
    Vue.component("ab",{
        template:"#addnum",
            data:function () {
                return {
                    number: 0
                };
            },
            methods:{
                 add(){
                this.number++;
             }
        }});
    let vue=new Vue(
        {
            el:"#app"
        }
    )
</script>
</body>
</html>
组件切换

用v-if 的方式进行组件的动态切换

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
    <button @click="toggle">按钮</button>
<photo v-if="isShow"></photo>
    <home v-else></home>
</div>
<template id="photo">
    <a href="vue-animation.html">lainjei</a>
</template>
<template id="home">
    <p>2222</p>
</template>
<script>
    Vue.component("photo",{
        template:"#photo",
    });
    Vue.component("home",{
        template:"#home",
    })
    let vue=new Vue({
        el:"#app",
        data:{
            name:"单佳兰",
            isShow:true
        },
        methods:{
            myFn(){
                alert("sjl");
            },
            toggle(){
                this.isShow=!this.isShow;
            }
        }
    });
</script>
</body>
</html>

这种方式并不是太专业,vue给我们提供了更加专业的做法进行[动态组件 & 异步组件]

语法:<component v-bind:is="currentTabComponent"></component>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
    <button @click="toggle">按钮</button>
    <component v-bind:is="name"></component>
</div>
<template id="photo">
    <a href="vue-animation.html">lainjei</a>
</template>
<template id="home">
    <div>
        <input type="checkbox">
        <span>2222</span>
    </div>
</template>
<script>
    Vue.component("photo",{
        template:"#photo",
    });
    Vue.component("home",{
        template:"#home",
    })
    let vue=new Vue({
        el:"#app",
        data:{
            isShow:true,
            name:'photo'
        },
        methods:{
            toggle(){
               this.name = this.name==='photo'? 'home':'photo';
            }
        }
    });
</script>
</body>
</html>

25.png

image.png


24.png

image.png


23.png

image.png


我们发现切换之后之前选中的状态不见了,那么怎么样保持之前的状态呢?Vue提供了Keep-alive

<div id="app">
    <button @click="toggle">按钮</button>
    <keep-alive>
        <component v-bind:is="name"></component>
    </keep-alive>
</div>

这样切换也可以保存之前的状态了

组件动画

给组件添加动画和给元素添加动画是一样的,不过不同的是过渡动画的离开和进入动画是同时进行的,要想不同时进行,必须给transition设置mode属性

<component v-bind:is="name"></component>
    </transition>

父子组件

父子组件数据传递
  1. 在Vue子组件不能访问父组件的数据,如果子组件想要访问父组件的数据,必须通过父组件传递
  2. 如何传递?
  • 在父组件中通过v-bind传递数据
    接受格式 v-bind:自定义接受名 = “要传递的数据”
  • 在子组件中通过props接收数据
    接收格式: props:[自定义接受名]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
    <father></father>
</div>
<template  id="father">
    <div>
        <p>我是父组件</p>
        <p>{{name}}---{{age}}</p>
// - 在父组件中通过v-bind传递数据
 //   接受格式 v-bind:自定义接受名 = “要传递的数据”
        <son :parentname="name" :parentage="age"></son>
    </div>
</template>
<template  id="son">
    <div>
        <p>我是子组件</p>
        <p>{{parentname}}---{{parentage}}</p>
    </div>
</template>
<script>
    Vue.component("father",{
        template:"#father",
        data:function (){
            return {name:"shanjialan",age:19};
        },
        components:{
            "son":{
                template: "#son",
//  - 在子组件中通过props接收数据
//    接收格式: props:[自定义接受名]
                props:["parentname","parentage"]
            }
        }
    });
    let vue=new Vue({
        el:"#app",
        data:{
            name:"单佳兰"
        },
        methods:{
            myFn(){
                alert("sjl");
            }
        }
    });
</script>
</body>
</html>
父子组件数据传递方法
  1. 在Vue子组件不能直接使用父组件的方法,如果子组件想要使用父组件的方法,必须通过父组件传递
  2. 如何传递?
  • 在父组件中通过v-on传递方法
    接受格式 v-on:自定义接受名 = “要传递的方法”
  • 在子组件methods中自定义一个方法,方法中通过this.$emit(自定义接收名)来接受方法
  • 在子组件中通过v-on绑定子组件的方法
    接收格式: @click=”子组件的方法"

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
    <father></father>
</div>
<template  id="father">
    <div>
        <button @click="say">parent</button>
        <p>我是父组件</p>
        <p>{{name}}---{{age}}</p>
 <!--   - 在父组件中通过v-on传递方法 -->
 <!--     接受格式 v-on:自定义接受名 = “要传递的方法” -->
        <son :parentname="name" :parentage="age" @parentsay="say"></son>
    </div>
</template>
<template  id="son">
    <div>
 <!--   - 在子组件中通过v-on绑定子组件的方法 -->
 <!--   接收格式: @click=”子组件的方法" -->
        <button @click="mySon">son</button>
        <p>我是子组件</p>
        <p>{{parentname}}---{{parentage}}</p>
    </div>
</template>
<script>
    Vue.component("father",{
        template:"#father",
        data:function (){
            return {name:"shanjialan",age:19};
        },
// - 在子组件methods中自定义一个方法,方法中通过this.$emit(自定义接收名)来接受方法
        methods: {
            say(){
                console.log("hello,father");
            }
        },
        components:{
            "son":{
                template: "#son",
                props:["parentname","parentage"],
                methods:{
                    mySon(){
                        this.$emit("parentsay");
                    }
                }
            }
        }
    });
    let vue=new Vue({
        el:"#app",
        data:{
            name:"单佳兰"
        },
        methods:{
            myFn(){
                alert("sjl");
            }
        }
    });
</script>
</body>
</html>
子组件给父组件方法传递参数

this.$emit(第一个参数,第二个参数)

  • 第一个参数,父组件需要传递的方法
  • 第二个参数,子组件给父组件传递的参数

this.$emit("parentsay","家和万事兴");

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
    <father></father>
</div>
<template  id="father">
    <div>
        <button @click="say">parent</button>
        <p>我是父组件</p>
        <p>{{name}}---{{age}}</p>
        <son :parentname="name" :parentage="age" @parentsay="say"></son>
    </div>
</template>
<template  id="son">
    <div>
        <button @click="mySon">son</button>
        <p>我是子组件</p>
        <p>{{parentname}}---{{parentage}}</p>
    </div>
</template>
<script>
    Vue.component("father",{
        template:"#father",
        data:function (){
            return {name:"shanjialan",age:19};
        },
        methods: {
            say(data){
                console.log("hello,father");
                console.log(data);
            }
        },
        components:{
            "son":{
                template: "#son",
                props:["parentname","parentage"],
                methods:{
                    mySon(){
                        //第一个参数,父组件需要传递的方法,第二个参数,子组件给父组件传递的参数
                        this.$emit("parentsay","家和万事兴");
                    }
                }
            }
        }
    });
    let vue=new Vue({
        el:"#app",
        data:{
            name:"单佳兰"
        },
        methods:{
            myFn(){
                alert("sjl");
            }
        }
    });
</script>
</body>
</html>
vue组件的命名注意点
  • 注册组件“驼峰命名法”,在使用时用“短横线”代替

<div id="app">
<!--    两者都可以-->
    <my-father></my-father>
    <my-Father></my-Father>
</div>
  • 如果想使用驼峰命名的数据,在传递时必须使用使用短横线+小写的方式,接受时自动转化为驼峰命名
  • 如果是传递方法,则不能用驼峰命名法,只能用短横线命名法

<son :parent-name="name" :parent-age="age" @parentsay="say"></son>

components:{
            "son":{
                template: "#son",
                props:["parentName","parentAge"],
                methods:{
                    mySon(){
                        //第一个参数,父组件需要传递的方法,第二个参数,子组件给父组件传递的参数
                        this.$emit("parentsay","家和万事兴");
                    }
                }
            }
        }

数据和方法多级传递

补充:

多层传递只能一层一层往下传递,不管是方法还是数据都是如此!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
<grandfather></grandfather>
</div>
<template  id="grandfather">
    <div>
        <button @click="say">爷爷</button>
        <p>{{name}}</p>
        <father :gfname="name" @gfsay="say"></father>
    </div>
</template>
<template  id="father">
    <div>
        <button @click="fathersay">爸爸</button>
        <p>{{gfname}}</p>
        <son :fname="gfname" @ssay="fathersay"></son>
    </div>
</template>
<template  id="son">
    <div>
        <button @click="sonsay">儿子</button>
        <p>{{fname}}</p>
    </div>
</template>
<script>
    Vue.component("grandfather",{
        template: "#grandfather",
        data:function (){
            return{
                name:"grandfather"
            }
        },
        methods: {
            say(){
                console.log("hello");
            }
        },
        components:{
            "father":{
                template:"#father",
                methods: {
                    fathersay() {
                        this.$emit("gfsay");
                    }
                },
                props:["gfname"],
                components: {
                    "son":{
                        template:"#son",
                        props: ["fname"],
                        methods:{
                            sonsay(){
                            this.$emit("ssay");
                            }
                        }
                    }
                }
            }
        }
    })
    let vue=new Vue({
        el:"#app",
        data:{
            name:"单佳兰"
        },
        methods:{
            myFn(){
                alert("sjl");
            }
        }
    });
</script>
</body>
</html>

21.png

image.png

vue匿名插槽

默认情况下是不能给子组件添加额外的内容的,如果想要添加,必须使用插槽,——插槽就像一个“坑”,由使用者根据自己的需求来填“坑”,如果不填坑,则显示默认数据,如果填坑的话则将添加的内容替换掉slot;

匿名插槽:有多少个匿名插槽,填充的数据则会拷贝几份;虽然我们可以制定多个匿名插槽,但是在企业开发中推荐只写一个匿名插槽,若一定要有几分,则使用具名插槽

具名插槽

由于匿名插槽的弊端,因此有了具名插槽来弥补不足

如何使用??

  1. 定义插槽的时候给slot指定name
  2. 填充的内容指定slot="name"来填充指定插槽

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
    <father>
        <div slot="one">111</div>
    </father>
    <son>
        <div slot="two">222</div>
    </son>
</div>
<template  id="son">
    <div>
        <p>头部</p>
        <slot name="one"></slot>
        <p>底部</p>
    </div>
</template>
<template  id="father">
    <div>
        <p>头部</p>
        <slot name="two"></slot>
        <p>底部</p>
    </div>
</template>
<script>
    Vue.component(
        "father",{
            template:"#father"
        }
    );
    Vue.component(
        "son",{
            template:"#son"
        }
    );
    let vue=new Vue({
        el:"#app",
        data:{
            name:"单佳兰"
        },
        methods:{
            myFn(){
                alert("sjl");
            }
        }
    });
</script>
</body>
</html>

v-slot指令

专门用于替换slot属性,vue推荐的方式

【注意点】v-slot只能添加在template标签上,v-slot:slotname,简写方式:#

<!--</html>-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
    <father>
        <template v-slot:two>
            <div>slot1</div>
            <div>slot11</div>
        </template>
    </father>
    <son>
        <template v-slot:one>
            <div>slot2</div>
            <div>slot22</div>
        </template>
    </son>
</div>
<template  id="son">
    <div>
        <p>头部</p>
        <slot name="one"></slot>
        <p>底部</p>
    </div>
</template>
<template  id="father">
    <div>
        <p>头部</p>
        <slot name="two"></slot>
        <p>底部</p>
    </div>
</template>
<script>
    Vue.component(
        "father",{
            template:"#father"
        }
    );
    Vue.component(
        "son",{
            template:"#son"
        }
    );
    let vue=new Vue({
        el:"#app",
        data:{
            name:"单佳兰"
        },
        methods:{
            myFn(){
                alert("sjl");
            }
        }
    });
</script>
</body>
</html>

作用域插槽

  1. 什么是作用域插槽?
    作用域插槽就是带数据的插槽,让父组件在填充子组件插槽的同时能够使用自组件的数据;
    作用域插槽的应用场景: 子组件提供数据, 父组件决定如何渲染

2.怎样使用作用域插槽?

2.1 先给自组件的插槽slot添加v-bind:外界访问的名称="需要暴露的数据"

2.2 在父组件添加的那个插槽<template>中添加slot-scope="scopename"属性接收数据

2.3 在template中通过`scopename.外界访问的名称"接收访问数据

v-bind:names="names"作用: 将子组件names数据暴露给父组件;

slot-scope="abc"作用: 接收子组件插槽暴露的数据

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="app">
<father></father>
</div>
<template id="father" >
    <son>
        <template slot-scope="abc">
            <li v-for="(name,index) in abc.names">{{name}}--{{index}}</li>
        </template>
    </son>
</template>
<template id="son">
    <div>
        <p>头部{{names}}</p>
        <slot v-bind:names="names"></slot>
        <p>底部</p>
    </div>
</template>
<script>
    Vue.component(
        "father", {
            template: "#father",
            components: {
                "son": {
                    template: "#son",
                    data: function () {
                        return {names: ["zs", "ls", "ww"]};
                    }
                }
            }
        }
    );
    let vue=new Vue({
        el:"#app",
        data:{
            name:"单佳兰"
        },
        methods:{
            myFn(){
                alert("sjl");
            }
        }
    });
</script>
</body>
</html>

20.png

image.png

v-slot指令
  • 在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。
    它取代了 slot 和 slot-scope
  • 也就是说我们除了可以通过v-slot指令告诉Vue内容要填充到哪一个具名插槽中,还可以通过v-slot指令告诉Vue如何接收作用域插槽暴露的数据
  • v-slot:插槽名称="作用域名称"
    匿名插槽名称为default

<template v-slot:default="abc">
      <li v-for="(name, index) in abc.names">{{name}}</li>
 </template>

简写:

<template #default="abc">
      <li v-for="(name, index) in abc.names">{{name}}</li>
 </template>


目录
相关文章
|
6天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
vue学习第四章
|
6天前
|
JavaScript 前端开发
vue学习第九章(v-model)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript与Vue的大一学生,自学前端2年半,正向全栈进发。此篇介绍v-model在不同表单元素中的应用及修饰符的使用,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
vue学习第九章(v-model)
|
6天前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
vue学习第十章(组件开发)
|
11天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
12天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
12天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
12天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
11天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
13天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
11天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
下一篇
无影云桌面