Vue学习笔记(二)组件化和模块化

Vue学习笔记(二)组件化和模块化

  • 前言
  • 组件化
    • 什么是组件化
    • 1、基础使用
    • 2、全局组件和局部组件
    • 3、语法糖和模板抽离
    • 4、组件的data为什么是函数
    • 5、父子组件
      • 5.1 父子组件
      • 5.2 父子组件通信
        • 5.2.1 父传子值
        • 5.2.2 子传父值
        • 5.2.3 父访问子
        • 5.2.4 子访问父
    • 6、插槽slot
      • 6.1 插槽的基本使用
        • 6.1.1 插槽的使用
        • 6.1.2 插槽的默认值
        • 6.1.3 多个值替换插槽
      • 6.2 具名插槽
        • 6.3 作用域插槽
  • 模块化
    • 什么是前端模块化
    • es5模块化解决方案
    • es6模块化解决方案

前言

本章记录一下vue的组件化和模块化,这是vue比较重要的知识点。会在实际开发中大量的使用到,因此,会比较详细的记录。
如需转载,请标明出处。
若发现问题,还望指正。

组件化

什么是组件化

组件化是一种思想,将一个复杂的页面分解成多个小的组件,每个组件都是独立的个体,互不影响,这样管理和维护起来就非常的容易。
组件化也是vue.js中重要的思想。
1、它提供了一种抽象,我们开发出一个个的组件来构成我们的应用。
2、每一个应用都可以抽象成一颗组件树。

1、基础使用

分为三个步骤:创建组件构造器 -> 注册组件 -> 使用组件

    <div id="app">
        
        <cpn>cpn>
    div>
    <script src="../js/vue.js">script>
    <script>
        // 步骤一:创建组件构造器
        const comp = Vue.extend({
      
            template: '
这是组件
'
}); // 步骤二:注册组件 Vue.component('cpn', comp); const app = new Vue({ el: '#app' });
script>

注意:前两个步骤必须放在创建vue实例之前,否者无效。
组件必须挂载在某个vue实例下,否者无效。

2、全局组件和局部组件

如上的使用方式即为全局组件的使用,它可以在任何的vue实例下使用,然后平时开发时通常都是使用局部组件。
局部组件的使用如下,在需要的vue中添加属性components,并进行注册,此时,只有在该vue实例里是可以使用该组件,其他地方皆不可使用。

    <div id="app">
        
        <cpn>cpn>
    div>
    <script src="../js/vue.js">script>
    <script>
        // 步骤一:创建组件构造器
        const comp = Vue.extend({
            template: '<div>这是组件2div>'
        });
        // 步骤二:注册组件
        // Vue.component('cpn', comp);
        const app = new Vue({
            el: '#app',
            components: {
                //cpn:组件的标签名
                //创建的组件名。步骤一的对象
                cpn: comp
            }
        });

3、语法糖和模板抽离

我们实际开发时是不会如上的方式去开发的,过于复杂了,我们会将代码进行简化,因为比较简单,此处直接上代码。

    <div id="app">
        <cpn>cpn>
    div>
    <template id="mytemp">
        <div>
            我是组件
        div>
    template>

    <script src="../js/vue.js">script>
    <script>
        const app = new Vue({
      
            el: '#app',
            components: {
      
                cpn: {
      
                    template: '#mytemp'
                }
            }
        });
    script>

模板抽离除了这种方式,还可以使用script标签的方式,此处不详细说明。
template标签里必须有且只有一个根标签

4、组件的data为什么是函数

本来是记住的,但是记录的时候就又忘记了,因此这里记录下来。
组件,是会复用的,如果将data设计成属性,那么,他们将指向同一个对象,一旦一个地方改变,复用的地方都会改变,这是有问题的。
如果设计成函数,函数是有作用域,因此每个组件都有自己的作用域,返回的都是自己的对象。不会影响其他组件的值。

5、父子组件

5.1 父子组件

父子组件即父组件和子组件,当一个组件在另一个组件里时,外层的组件即为里层组件的父组件,里层组件为子组件
vue实例为root组件,即根组件,也是它里面组件的父组件。

5.2 父子组件通信

5.2.1 父传子值

父传子值主要使用到了props属性,它是一个数组,里面每一个值都是字符串,如下。props里的值为val,在父组件里使用时,需要用到v-bind。

    <div id="app">
        <cpn :val='vals'>cpn>
    div>
    <template id="mytemp">
        <div>
            我是组件 {
    {val}}
        div>
    template>

    <script src="../js/vue.js">script>
    <script>
        const app = new Vue({
      
            el: '#app',
            data: {
      
                vals: '这是父传子值'
            },
            components: {
      
                cpn: {
      
                    template: '#mytemp',
                    props: ['val']
                }
            }
        });
    script>

5.2.2 子传父值

需要注意两点:
1、按钮上的属性是@click,而非@onclick
2、this.$emit(‘bclick’, “hello”)需要加this

<div id="app">
        <cpn @bclick="btnClick">cpn>
    div>
    <template id="mytemp">
        <div>
            我是组件
            <button @click="ccc">按钮button>
        div>
    template>

    <script src="../js/vue.js">script>
    <script>
        const app = new Vue({
      
            el: '#app',
            data: {
      
                vals: '这是父传子值'
            },
            methods: {
      
                btnClick(val) {
      
                    console.log(val);
                }
            },
            components: {
      
                cpn: {
      
                    template: '#mytemp',
                    methods: {
      
                        ccc() {
      
                            this.$emit('bclick', "hello")
                        }
                    }
                }
            }
        });
    script>

5.2.3 父访问子

父组件访问子组件的内容,如方法、属性等。
children:

children这个很少使用,通常我们获取子组件的内容不使用它,一般在获取所有子组件时才使用

<div id="app">
        <button @click="btnClick">父访问子button>
        <cpn>cpn>
    div>
    <template id="mytemp">
        <div>
            我是组件
        div>
    template>

    <script src="../js/vue.js">script>
    <script>
        const app = new Vue({
      
            el: '#app',
            data: {
      
                vals: 'parent'
            },
            methods: {
      
                btnClick(val) {
      
                    console.log(this.$children[0].va);
                    this.$children[0].ccc();
                }
            },
            components: {
      
                cpn: {
      
                    template: '#mytemp',
                    data() {
      
                        return {
      
                            va: 'son'
                        }
                    },
                    methods: {
      
                        ccc() {
      
                            console.log("this is child");
                        }
                    }
                }
            }
        });
    script>
son
this is child

这里打印出this.$children[0]的值可见子组件的内容。如下
在这里插入图片描述

refs:
既然不适用children,那么肯定有其他的代替,没错,就是refs,它的使用可以规避掉children的弊端(children需要下标去获取对应的组件,一旦动态改变的组件的顺序等就无法准确获取到相应的子组件)。
它的使用需要在父组件的子组件标签中添加ref=“”的属性,类似于id的意思,需要唯一。然后再通过this.$refs获取对应的子组件。

<div id="app">
        <button @click="btnClick">按钮button>
        <cpn>cpn>
        <cpn ref="aa">cpn>
        <cpn ref="bb">cpn>
    div>
    <template id="mytemp">
        <div>
            我是组件

        div>
    template>

    <script src="../js/vue.js">script>
    <script>
        const app = new Vue({
      
            el: '#app',
            data: {
      
                vals: 'parent'
            },
            methods: {
      
                btnClick() {
      
                    this.$refs.aa.c1();
                }
            },
            components: {
      
                cpn: {
      
                    template: '#mytemp',
                    data() {
      
                        return {
      
                            va: 'son'
                        }
                    },
                    methods: {
      
                        c1() {
      
                            console.log("子组件1");
                        },
                        c2() {
      
                            console.log("子组件2");
                        },
                        c3() {
      
                            console.log("子组件3");
                        }
                    }
                }
            }
        });
    script>

5.2.4 子访问父

子组件访问父组件的内容,如方法、属性等。
子访问父可以使用 p a r e n t , 它 的 使 用 与 parent,它的使用与 parent使children类似。这里就不再赘述。并且它使用的很少,因为如果使用了它就意味着于父组件的耦合度高了,不利于开发。
还有另一个属性$root,它可以获取到顶级父元素,也就是vue实例的内容。不过它同样使得的比较少,此处也不再多说。

6、插槽slot

6.1 插槽的基本使用

6.1.1 插槽的使用

以前的代码是不具备扩展的,但是有了插槽就不一样了,可以很好的扩展,也可以很好的自定义。
在子组件需要扩展的地方使用上slot,然后在父组件的子组件标签中写入需要的内容即可。

<div id="app">
        <cpn><button>按钮button>cpn>
        <cpn><span>嘿嘿span>cpn>
        <cpn><i>hhhai>cpn>
    div>
    <template id="mytemp">
        <div>
            我是组件
            <slot>slot>
        div>
    template>

    <script src="../js/vue.js">script>
    <script>
        const app = new Vue({
      
            el: '#app',
            components: {
      
                cpn: {
      
                    template: '#mytemp'
                }
            }
        });
    script>

6.1.2 插槽的默认值

如果插槽里有很多地方都需要使用相同的内容,此时我们就可使用默认值,那么不使用默认值的地方加入新内容即可,其他需要就可以不写内容了。

<div id="app">
        <cpn>cpn>
        <cpn><span>嘿嘿span>cpn>
        <cpn><i>hhhai>cpn>
    div>
    <template id="mytemp">
        <div>
            我是组件
            <slot><button>按钮button>slot>
        div>
    template>

6.1.3 多个值替换插槽

如果需要插入多个标签的内容,也是可以的,他会直接将这些内容整体替换。

嘿嘿 呵呵呵呵呵呵 哈哈 hhha

6.2 具名插槽

说简单点,就是给插槽取个名字,使用的时候指明替换哪一个,例如导航组件部分,html内容部分如下。

    <div id="app">
        <cpn><button slot="center">替换button>cpn>
    div>
    <template id="mytemp">
        <div>
            <slot name="left"><button>button>slot>
            <slot name="center"><button>button>slot>
            <slot name="right"><button>button>slot>
        div>
    template>

6.3 作用域插槽

**slot-scope: **被废弃了,但是也能使用
组件是有作用域的,父子之间也是可以进行通信的。
使用插槽的时候也会涉及到作用域。当父组件需要使用子组件的值时,需要将值抛出,父组件通过slot-scope进行获取。下面的方式可能有些过时,如下。

<div id="app">
        <cpn>cpn>
        <cpn>
            <div slot-scope="slot2">
                <span v-for="item in slot2.data">{
    {item}} span>
            div>
        cpn>
        <cpn>
            <div slot-scope="slot3">
                <span>{
    {slot3.data.join(" - ")}}span>
            div>
        cpn>
    div>
    <template id="mytemp">
        <div>
            <slot :data="comics">
                <ul>
                    <li v-for="item in comics">{
    {item}}li>
                ul>
            slot>
        div>
    template>

    <script src="../js/vue.js">script>
    <script>
        const app = new Vue({
      
            el: '#app',
            components: {
      
                cpn: {
      
                    template: '#mytemp',
                    data() {
      
                        return {
      
                            comics: ['斗破苍穹', '斗罗大陆', '灵笼', '完美世界', '雾山五行', '吞噬星空']
                        }
                    }
                }
            }
        });
    script>

Vue学习笔记(二)组件化和模块化_第1张图片
**v-slot:**新版本使用

<div id="app">
        <cpn>
            <template v-slot:default="slot2">
                <span>{
    {slot2.data}} span>
            template>
        cpn>
    div>
    <template id="mytemp">
        <div>
            <slot :data="comics">
                <ul>
                    <li v-for="item in comics">{
    {item}}li>
                ul>
            slot>
        div>
    template>

独占默认插槽的缩写语法:
在上述情况下,当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot 直接用在组件上:

	<div id="app">
        <cpn v-slot:default="slot2">
            <span>{
    {slot2.data}} span>
        cpn>
    div>

这种写法还可以更简单。就像假定未指明的内容对应默认插槽一样,不带参数的 v-slot 被假定对应默认插槽:

	<div id="app">
        <cpn v-slot="slot2">
            <span>{
    {slot2.data}} span>
        cpn>
    div>

只要出现多个插槽,请始终为所有的插槽使用完整的基于 的语法:也就是简写前的方式

模块化

背景:JavaScript设计初期只是实现简单的页面交互逻辑,当时的js代码直接写在script标签里。但是随着各方面的发展,很多后端的业务逻辑交给了前端完成,比如表单验证等,特别是随着ajax的广泛应用,前端的代码量迅速增长,使得不能使用原来的方式,这时,大量的js代码放入了js文件中,通过外部引入进html中,但是也会出现一些问题,比如命名问题,数据共享等,模块化就应运而生。

什么是前端模块化

将一个复杂的程序依据一定的规范封装成多个部分(文件),每个部分的内部数据和实现都是独立的,对外暴露一部分内容供其他部分调用。

es5模块化解决方案

在es5(ECMAScript第五个版本)中,为了解决作用域的问题,很多时候我们都是通过闭包的形式。但是,使用闭包也会有它的问题,比如,一个js文件确实需要用到另一个js里的变量、函数等。不重写几乎是用不到的。因为此时每个js都是一个独立的作用域,无法相互使用。
我们会通过返回对象、再调用的方式去解决。如下。
a.js

var module1 = (function () {
     
    let obj = {
     }
    let name = '张三'

    obj.name = name

    return obj
})()

c.js

(function () {
     
    console.log(module1.name);
})()

此处需要注意的是module1 不能重复,每一个模块使用唯一的名称

es6模块化解决方案

到了es6(ECMAScript第六个版本),自带了模块化。只需在html引用js时添加属性type=“module”,并在js使用export和import完成。

	<script src="./a.js" type="module">script>
    <script src="./c.js" type="module">script>

a.js

let name = '张三'
export {
     
    name
}

c.js

import {
      name } from './a.js'
console.log(name);

export不仅可以导出变量,还可以将函数、类等导出,并且还能不在最后导出,声明时就导出。如下

export function sum(num1,num2){
     
    return num1 + num2
}

你可能感兴趣的:(Vue,vue,js,javascript,java,html)