IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue学习之组件化开发 -> 正文阅读

[JavaScript知识库]vue学习之组件化开发

vue学习之组件化开发

1、认识组件化

1.1、什么是组件化

image-20210928093709443

  • 人们面对复杂问题的处理方式

    • 任何一个人处理信息的逻辑能力都是有限的
    • 所以,当面对一个非常复杂的问题时,我们不太可能一次性搞定一大堆的内容
    • 但是我们有一种天生的能力,就是将问题进行拆解
    • 如果将一个复杂的问题拆分很多歌可以处理的小问题,再将其放在整体中,你会发现大的问题也会迎刃而解
  • 组件化也是类似的思想

    • 如果我们将一个页面中所有的处理逻辑全部放在一起处理起来就会变得非常复杂,而且不利于后续的管理和扩展
    • 如果我们将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护变得非常容易

1.2、Vue组件化思想

  • 组件化是vue.js中的重要思想
    • 它体用了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用
    • 任何的应用都会被抽象成一颗组件树

image-20210928094009263

  • 组件化思想的应用

    • 有了组件化的思想,我们在之后的开发中要充分利用它
    • 尽可能将页面拆分成一个个小的、可复用的组件
    • 这样让我们的代码更加方便组件和管理,并且扩展性更强

2、组件化基础

2.1、注册组件

注册组件的基本步骤

  • 组件的使用分为三个步骤

    • 创建组件构造器
    • 注册组件
    • 使用组件
  • 看一下通过代码如何注册组件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>01-组件化的基本使用</title>
  </head>
  <body>
    <div id="app">
      <!-- 3、使用组件 -->
      <my-cpn/>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script>
      // 1、创建组件构造器对象
      const cpnC = Vue.extend({
          template:`
            <div>
              <h2>我是标题</h2>
              <p>我是内容,哈哈</p>
              <p>我是内容,嘿嘿</p>
            </div>
          `
      });

      // 2、注册组件
      Vue.component('my-cpn',cpnC);

      const app = new Vue({
          el:"#app",
          data:{
              message:"小朋友,你是否有很多问号"
          }
      })
    </script>
  </body>
</html>

image-20210928095746326image-20210928095835294

注册组件步骤解析

  • Vue.extend()

    • 调用Vue.extend()创建的是一个组件构造器
    • 通常在创建组件构造器时,传入template代表我们自定义组件的模板
    • 该模板就是我们在使用组件的地方,要显示的HTML代码
    • 事实上,这种写法Vue2.x文档中几乎看不到了,它会直接使用我们下面讲到的语法糖,但是很多资料还是会提及这种方式,而且这种方式是学习后面的基础
  • Vue.component()

    • 调用该方法是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称
    • 所以需要传递两个参数:1、注册组件的标签名 2、组件构造器
  • 组件必须挂在在某个Vue实例上,否则不会生效

    • 我们来看下面使用了三次
    • 其实第三次没有生效

image-20210928101122467

第三步的解析

image-20210928103746276

组件其他内容

全局组件和局部组件

  • 全局组件:当我们通过调用Vue.component()注册组件时,组件的注册是全局的
    这意味着该组件可以在任意Vue示例下使用。

image-20210928105344797

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
        <cpn><cpn>
    </div>  
    <div id="app1">
        <cpn></cpn>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script>
      // 1、组件构造器
      const cpnCom = Vue.extend({
        template: `
              <div>
                <h2>这是组件标题</h2>
                <span>组件内容</span>
                </div>
            `
          });
          Vue.component('cpn', cpnCom);
          
      const app = new Vue({
          el:"#app",
          data:{
              msg:"看看"
          }
      });

      const app1 = new Vue({
          el:"#app1"
      })
    </script>
  </body>
</html>
  • 局部组件:如果我们注册的组件是挂载在某个实例中, 那么就是一个局部组件。

image-20210928104415521

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
        <cpn><cpn>
    </div>  
    <div id="app1">
        <cpn></cpn>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script>
      // 1、组件构造器
      const cpnCom = Vue.extend({
        template: `
              <div>
                <h2>这是组件标题</h2>
                <span>组件内容</span>
                </div>
            `
          });
          
      const app = new Vue({
          el:"#app",
          data:{
              msg:"看看"
          },
          components:{
            cpn:cpnCom
          }
      });

      const app1 = new Vue({
          el:"#app1"
      })
    </script>
  </body>
</html>

image-20210928105631386

父组件和子组件

  • 在前面我们看到了组件树:

    • 组件和组件之间存在层级关系
    • 而其中一种非常重要的关系就是父子组件的关系
  • 父子组件错误用法:以子标签的形式在Vue实例中使用

    • 因为当子组件注册到父组件的components时,Vue会编译好父组件的模块
    • 该模板的内容已经决定了父组件将要渲染的HTML(相当于父组件中已经有了子组件中的内容了)
    • 是只能在父组件中被识别的。
    • 类似这种用法,是会被浏览器忽略的。

image-20210928141107362

注册组件语法糖

image-20210928144048049

说明

  • vue为了简化这个过程,提供了注册的语法糖
  • 主要是省却了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替

模板的分离写法

  • 我们通过语法糖简化了vue组件的注册过程,另外还有一个地方写法比较麻烦,就是template模板写法
  • 如果我们能将其中html分离出来,然后挂载对应组件上,结构必然清晰明了
  • 有两种方案定义HTML模板内容

使用script标签

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>05-模板分离方式</title>
  </head>
  <body>
    <div id="app">
        <cpn />
    </div>
    <!-- 方案一:通过script标签实现定义HTML模板 -->
    <script type="text/x-template" id="cpn">
      <div>
          <h2>我是标题</h2>
          <p>我是内容</p>
      </div>
    </script>
    
 
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script>
      // 1、注册一个全局组件
      Vue.component("cpn", {
        template: "#cpn",
      });

      // 2、创建vue实例对象
      const app = new Vue({
        el: "#app",
      });
    </script>
  </body>
</html>

使用template标签

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>05-模板分离方式</title>
  </head>
  <body>
    <div id="app">
        <cpn />
    </div>
    
    <!-- 方案二、通过template标签实现定义HTML模板 -->
    <template id="cpn">
        <div>
            <h2>我是标题</h2>
            <p>我是内容</p>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script>
      // 1、注册一个全局组件
      Vue.component("cpn", {
        template: "#cpn",
      });

      // 2、创建vue实例对象
      const app = new Vue({
        el: "#app",
      });
    </script>
  </body>
</html>

2.2、数据传递

组件可以访问vue实例数据吗

  • 组件是一个单独功能模块的封装,这个模块有属于自己的HTML模板,也应该有属于自己的数据data.
  • 分析组件中数据存放在哪里
  • 不妨来测试组件中能不能访问vue实例中data
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>06-测试组件访问vue实例数据</title>
</head>
<body>
    <div id="app">
<my-cpn></my-cpn>
    </div>
    <template id="myCpn">
        <div>{{msg}}</div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const app = new Vue({
    el:"#app",
    data:{
        msg:"消息"
    }
    components:{
      'my-cpn':{
          template:'#myCpn'
      }
    }
})
    </script>
</body>
</html>

image-20210928150244791

解析:组件去访问msg,msg定义在vue中我们发现最终并没有发现显示结果,结论组件是不能直接访问vue实例中的data数据;我们发现不能访问,即使可以访问,如果将所有的数据都放在vue实例中,vue实例变得非常臃肿;总而言之,vue组件应该有自己保存数据的地方。

组件数据的存放

  • 那组件自己的数据存放在哪里呢?
    • 组件对象也有一个data属性(也可以有methods等属性,下面用到)
    • 只是这个data属性必须是一个函数
    • 并且这个函数返回一个对象,对象里面存放数据
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>06-测试组件访问vue实例数据</title>
</head>
<body>
    <div id="app">
<my-cpn></my-cpn>
    </div>
    <template id="myCpn">
        <div>{{msg}}</div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const app = new Vue({
    el:"#app",
    components:{
      'my-cpn':{
          template:'#myCpn',
          data(){
              return {
                  msg:"are you ready"
              }
          }
      }
    }
})
    </script>
</body>
</html>

image-20210928151132034

为什么是一个函数

  • 首先如果不是一个函数,vue直接报错
  • 其次,原因在于vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的话,组件在多次使用后相互影响

data为什么是函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>07-data为什么是函数</title>
</head>
<body>
    <div id="app">
      <cpn></cpn>
      <cpn></cpn>
      <cpn></cpn>
      <cpn></cpn>
      <cpn></cpn>
      <cpn></cpn>
      <cpn></cpn>
    </div>
    <template id = "myCpn">
        <div>
            当前计数:{{counter}}
            <button @click="increment">+</button>
            <button @click="decrement">-</button>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script>
        // 1、注册组件
        const obj = {
            counter:0
        };
        // 注册全局组件语法糖
        Vue.component('cpn',{
            template:'#myCpn',
            data(){
                return obj;
            },
            methods:{
                increment(){
                    this.counter++;
                },
                decrement(){
                    this.counter--;
                }
            }
        });

        // 创建vue实例对象
        const app = new Vue({
            el:"#app",
            data:{
                mes:"klk"
            }
        })
    </script>
</body>
</html>

父子组件之间的通信

  • 在上一小节中,我们提到了子组件是不能引用父组件或者vue实例的数据的
  • 但是开发中,往往需要一些数据确实从上层传递给下层
    • 比如一个页面中,我们从服务器请求里面获取很多数据
    • 其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示的
    • 这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)
  • 如何进行父子组件之间的通信的?vue官方提到两种方案

image-20210928154029434

  • 通过props向子组件传递数据

  • 通过事件向父组件发送消息

props基本使用

  • 使用props来生命需要从父级接收到的数据
  • props值两种方式
    • 字符串数组,数组中的字符串就是传递时的名称
    • 对象,对象可以设置传递时的类型,可以设置默认值
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>08-父传子props使用</title>
</head>
<body>
    <div id="app">
        <!-- message:表示父组件中定义变量对应,movies是类似的 -->
        <cpn :cmessage="message" :cmovies="movies"></cpn>
    </div>
    <!-- 子组件cpn -->
    <template id="myCpn">
        <div>
            <ul>
                <li v-for="item in cmovies">{{item}}</li>
            </ul>
            <span>{{cmessage}}</span>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script>
        Vue.component('cpn',{
            template:"#myCpn",
            data(){
                return{                    
                }
            },
            props:{
                cmessage:{
                    // 类型
                    type:String,
                    // 默认值
                    default:"默认消息",
                    // 必传
                    required:true
                },
                cmovies:{
                    type:Array,
                    // 默认值是工厂函数返回数组
                    default(){
                        return []
                    }
                }

            }
        });
        const app = new Vue({
            el:"#app",
            data:{
                message:"hello everybody",
                movies:[
                    "大秦帝国","钢铁侠","水浒传"
                ]
            }
        })
    </script>
</body>
</html>

props数据验证

  Vue.component('my-com',{
            props:{
                // 基础的类型检查('null' 匹配任何类型)
                propA:Number,
                // 多个可能的类型
                propB:[String,Number],
                // 必填的字符串
                propC:{
                    type:String,
                    required:true
                },
                // 带有默认值的数字
                propD:{
                    type:Number,
                    default:100
                },
                // 带有默认值的对象
                propE:{
                    type:Object,
                    // 对象或者数组默认值必须从工厂函数获取
                    default(){
                        return{}
                    }
                },
                // 自定义验证函数
                propF:{
                    validator(value){
                        // 这个value必须是下列字符串中一个
                        return ['success','warning','danger'].indexOf(value) !== -1;
                    }
                }
            }
        })

父传子props驼峰标识

image-20210928162725039

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>09-父传子props驼峰标识</title>
</head>
<body>
    <div id="app">
      <cpn :c-info="info" :child-my-message="message"></cpn>
    </div>
    <template id="myCpn">
      <div>
        <h2> {{cInfo}}</h2>
        <h2>{{childMyMessage}}</h2>
      </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script>
      Vue.component('cpn',{
          template:"#myCpn",
          props:{
              cInfo:{
                  type:Object,
                  default(){
                      return {}
                  }
              },
              childMyMessage:{
                  type:String,
                  default:''
              }
          }
      });
      const app = new Vue({
          el:"#app",
          data:{
             info:{
                 name:"geekmice",
                 age:98,
                 sex:"男"
             },
             message:"快来解决了"
          }
      })
    </script>
</body>
</html>

子级向父级传递

  • props用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中。
  • 我们应该如何处理呢?这个时候,我们需要使用自定义事件来完成。
  • 什么时候需要自定义事件呢?
    • 当子组件需要向父组件传递数据时,就要用到自定义事件了。
    • 我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。
  • 自定义事件的流程:
    • 在子组件中,通过$emit()来触发事件
    • 在父组件中,通过v-on来监听子组件事件。

案例说明

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>10-子传父(自定义事件)</title>
  </head>
  <body>
    <!-- 父组件 -->
    <div id="app">
      <cpn @item-click="cpnClick"></cpn>
    </div>

    <!-- 子组件 -->
    <template id="myCpn">
      <div>
        <button v-for="item in categories" @click="btnClick(item)">
          {{item.name}}
        </button>
      </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script>
      const cpn = {
        template: "#myCpn",
        data() {
          return {
            categories: [
              { id: "aaa", name: "热门推荐" },
              { id: "bbb", name: "手机数码" },
              { id: "ccc", name: "家勇家电" },
              { id: "ddd", name: "电脑办公" },
            ],
          };
        },
        methods: {
          btnClick(item) {
            //  发射事件
            this.$emit("item-click", item);
          },
        },
      };

      //   父组件
      const app = new Vue({
        el: "#app",
        data: {
          message: "kkk",
        },
        components: {
          cpn
        },
        methods: {
          cpnClick(item) {
            console.log(item);
          },
        },
      });
    </script>
  </body>
</html>

image-20211002151241089

父子组件访问

  • 有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问根组件
    • 父组件访问子组件: c h i l d r e n 或 者 children或者 childrenrefs
    • 子组件访问父组件
  • $children的访问
    • this.$children是一个数组类型,它包括所有子组件对象
    • 遍历去除所有子组件的message状态

父组件访问子组件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

<div id="app">
  <cpn></cpn>
  <cpn ref="abc"></cpn>

  <cpn ref="aaa"></cpn>
  <button @click="btnClick">按钮</button>
</div>
<!-- 定义HTML模板,模板分离 -->
<template id="cpn">
  <div>我是子组件</div>
</template>
<!-- <script src="../js/vue.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>

<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    },
    methods: {
      btnClick() {
        // 1.$children 返回值是子组件数组
        console.log(this.$children);
        for (let c of this.$children) {
          console.log(c.name);
          c.showMessage();
        }
        // console.log(this.$children[3].name);

        // 2.$refs => 返回值是对象类型, 默认是一个空的对象 ref='bbb'
        console.log(typeof this.$refs); // object
        console.log(this.$refs); // {abc: a, aaa: a}
        // console.log(this.$refs.aaa.name);
      }
    },
    // 局部组件方式,只能在当前vue实例使用
    components: {
      cpn: {
        // 模板分离
        template: '#cpn',
        // 子组件定义变量,以对象方式返回
        data() {
          return {
            name: '我是子组件的name'
          }
        },
        // 子组件涉及的方法
        methods: {
          showMessage() {
            console.log('showMessage');
          }
        }
      },
    }
  })
</script>

</body>
</html>

效果演示

父组件访问子组件

案例演示说明

image-20211007172045115

子组件访问父组件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<!--根组件vue实例-->
<div id="app">
  <cpn></cpn>
</div>
<!-- 定义的HTML子组件cpn -->
<template id="cpn">
  <div>
    <h2>我是cpn组件</h2>
    <!-- 子组件包含子子组件 -->
    <ccpn></ccpn>
  </div>
</template>
<!-- 定义的HTML子子组件ccpn -->
<template id="ccpn">
  <div>
    <h2>我是子组件</h2>
    <button @click="btnClick">按钮</button>
  </div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    },
    // 定义局部组件
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            name: '我是cpn组件的name'
          }
        },
        // 局部组件内部包含局部组件信息
        components: {
          ccpn: {
            template: '#ccpn',
            methods: {
              btnClick() {
                // 1.访问父组件$parent 也就是cpn
                console.log(this.$parent);
                console.log(this.$parent.name);

                // 2.访问根组件$root 也就是vue实例
                console.log(this.$root);
                console.log(this.$root.message);
              }
            }
          }
        }
      }
    }
  })
</script>

</body>
</html>

效果展示

子组件访问父组件

案例效果说明

image-20211007173655777

非父子组件访问

3、组件化高级

3.1、插槽slot

编译作用域

  • 在真正学习插槽之前,我们需要先理解一个概念:编译作用域。
  • 官方对于编译的作用域解析比较简单,我们自己来通过一个例子来理解这个概念:
    我们来考虑下面的代码是否最终是可以渲染出来的:
  • 中,我们使用了isShow属性。
  • isShow属性包含在组件中,也包含在Vue实例中。
  • 答案:最终可以渲染出来,也就是使用的是Vue实例的属性。
  • 为什么呢?
    • 官方给出了一条准则:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。
    • 而我们在使用的时候,整个组件的使用过程是相当于在父组件中出现的。
    • 那么他的作用域就是父组件,使用的属性也是属于父组件的属性。
      因此,isShow使用的是Vue实例中的属性,而不是子组件的属性。

案例演示

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

<div id="app">
  <cpn v-show="isShow"></cpn>
  <cpn v-for="item in names"></cpn>
</div>

<template id="cpn">
  <div>
    <h2>我是子组件</h2>
    <p>我是内容, 哈哈哈</p>
    <button v-show="isShow">按钮</button>
  </div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      isShow: true
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            isShow: false
          }
        }
      },
    }
  })
</script>

</body>
</html>

效果展示

为什么使用插槽slot

  • slot翻译为插槽:

  • 在生活中很多地方都有插槽,电脑的USB插槽,插板当中的电源插槽。

  • 插槽的目的是让我们原来的设备具备更多的扩展性。、

  • 比如电脑的USB我们可以插入U盘、硬盘、手机、音响、键盘、鼠标等等。

  • 组件的插槽:

    • 组件的插槽也是为了让我们封装的组件更加具有扩展性。

    • 让使用者可以决定组件内部的一些内容到底展示什么。、

      栗子:移动网站中的导航栏。

      • 移动开发中,几乎每个页面都有导航栏。
      • 导航栏我们必然会封装成一个插件,比如nav-bar组件。
      • 一旦有了这个组件,我们就可以在多个页面中复用了。
      • 但是,每个页面的导航是一样的吗?No,我以京东M站为例

image-20211007175052441

如何封装这类组件slot

  • 如何去封装这类的组件呢?
    • 它们也很多区别,但是也有很多共性。
    • 如果,我们每一个单独去封装一个组件,显然不合适:比如每个页面都返回,这部分内容我们就要重复去封装。
    • 但是,如果我们封装成一个,好像也不合理:有些左侧是菜单,有些是返回,有些中间是搜索,有些是文字,等等。
  • 如何封装合适呢?抽取共性,保留不同。
    • 最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽。
    • 一旦我们预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容。
      是搜索框,还是文字,还是菜单。由调用者自己来决定。
  • 这就是为什么我们要学习组件中的插槽slot的原因。

slot基本使用

  • 了解了为什么用slot,我们再来谈谈如何使用slot?
    • 在子组件中,使用特殊的元素就可以为子组件开启一个插槽。
    • 该插槽插入什么内容取决于父组件如何使用。
      • 我们通过一个简单的例子,来给子组件定义一个插槽:
        中的内容表示,如果没有在该组件中插入任何其他内容,就默认显示该内容
        有了这个插槽后,父组件如何使用呢?

image-20211007175348454

具名插槽

  • 当子组件的功能复杂时,子组件的插槽可能并非是一个。
    • 比如我们封装一个导航栏的子组件,可能就需要三个插槽,分别代表左边、中间、右边。
    • 那么,外面在给插槽插入内容时,如何区分插入的是哪一个呢?
    • 这个时候,我们就需要给插槽起一个名字
  • 如何使用具名插槽呢?
    • 非常简单,只要给slot元素一个name属性即可
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

<div id="app">
  <cpn><span slot="center">标题</span></cpn>
  <cpn><button slot="left">返回</button></cpn>
</div>


<template id="cpn">
  <div>
    <slot name="left"><span>左边</span></slot>
    <slot name="center"><span>中间</span></slot>
    <slot name="right"><span>右边</span></slot>
  </div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    },
    components: {
      cpn: {
        template: '#cpn'
      }
    }
  })
</script>

</body>
</html>

image-20211007194041371

作用域插槽

是需要在插槽slot上绑定数据的。然后组件模板根据slot上绑定的数据进行操作。

  • 在父组件使用我们的子组件时,从子组件中拿到数据

  • 我们通过获取到slotProps属性

  • 在通过slotProps.data就可以获取到刚才我们传入的data了

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

<div id="app">
  <cpn></cpn>

  <cpn>
    <!--目的是获取子组件中的pLanguages-->
    <!-- slot-scope:表示子组件的数据 -->
    <template slot-scope="slot">
      <!--<span v-for="item in slot.data"> - {{item}}</span>-->
      <span>{{slot.data.join(' - ')}}</span>
    </template>
  </cpn>

  <cpn>
    <!--目的是获取子组件中的pLanguages-->
    <template slot-scope="slot">
      <!--<span v-for="item in slot.data">{{item}} * </span>-->
      <span>{{slot.data.join(' * ')}}</span>
    </template>
  </cpn>
  <!--<cpn></cpn>-->
</div>

<template id="cpn">
  <div>
    <slot :data="pLanguages">
      <ul>
        <li v-for="item in pLanguages">{{item}}</li>
      </ul>
    </slot>
  </div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            pLanguages: ['JavaScript', 'C++', 'Java', 'C#', 'Python', 'Go', 'Swift']
          }
        }
      }
    }
  })
</script>
</body>
</html>

3.2、动态组件

3.3、异步组件

4、组件生命周期

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-08 11:42:45  更:2021-10-08 11:43:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 4:09:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计