3.1、组件的使用

3.1、什么是组件

3.1.1、传统方式开发的应用

一个网页通常包括三部分:结构(HTML)、样式(CSS)、交互(JavaScript)

3.1.2、组件化方式开发的应用

使用组件化方式开发解决了以上的两个问题:

① 每一个组件都有独立的js,独立的css,这些独立的js和css只供当前组件使用,不存在纵横交错。更加便于维护。

② 代码复用性增强。组件不仅让js css复用了,HTML代码片段也复用了(因为要使用组件直接引入组件即可)。

3.1.3、什么是组件?

① 组件:实现应用中局部功能的代码和资源的集合。凡是采用组件方式开发的应用都可以称为组件化应用

② 模块:一个大的js文件按照模块化拆分规则进行拆分,生成多个js文件,每一个js文件叫做模块。凡是采用模块方式开发的应用都可以称为模块化应用

③ 任何一个组件中都可以包含这些资源:HTML CSS JS 图片 声音 视频等。从这个角度也可以说明组件是可以包括模块的。

3.1.4、组件的划分粒度很重要

粒度太粗会影响复用性。为了让复用性更强,Vue的组件也支持父子组件嵌套使用。

子组件由父组件来管理,父组件由父组件的父组件管理。在Vue中根组件就是vm。因此每一个组件也是一个Vue实例。

3.2、组件的创建,注册,使用

3.2.1、组件的创建、注册、局部使用

第一步:创建组件

Vue.extend({该配置项和new Vue的配置项几乎相同,略有差别})

区别有哪些?

1. 创建Vue组件的时候,配置项中不能使用el配置项。

因为组件具有通用性,不特定为某个容器服务,它为所有容器服务

2. 配置项中的data不能使用直接对象的形式,必须使用function

以保证数据之间不会相互影响

3、使用template配置项来配置模板语句:HTML结构

第二步:注册组件

局部注册:

在配置项当中使用components,语法格式:

components : {

组件的名字 : 组件对象

}

全局注册:

第三步:使用组件

1、直接在页面中写<组件的名字></组件的名字>

2、也可以使用单标签<组件的名字 />

这种方式一般在脚手架中使用,否则会有元素不渲染的问题

<body>
    <div id="app">
      <h1>{{msg}}</h1>
      <!-- 3. 使用组件 -->
      <userlist></userlist>
    </div>

    <script>
      // 1.创建组件(结构HTML 交互JS 样式CSS)
      const myComponent = Vue.extend({
        template: `
            <ul>
                <li v-for="(user,index) of users" :key="user.id">
                    {{index}},{{user.name}}
                </li>
            </ul>
            `,
        data() {
          return {
            users: [
              { id: "001", name: "jack" },
              { id: "002", name: "lucy" },
              { id: "003", name: "james" },
            ],
          };
        },
      });

      // Vue实例
      const vm = new Vue({
        el: "#app",
        data: {
          msg: "第一个组件",
        },
        // 2. 注册组件(局部注册)
        components: {
          // userlist是组件的名字。myComponent只是一个变量名。
          userlist: myComponent,
        },
      });
    </script>
  </body>

3.2.2、为什么组件中data数据要使用函数形式

面试题:为什么组件中data数据要使用函数形式

 <script>
      // 数据只有一份,数据会互相影响
      let dataobj = {
        counter: 1,
      };
      let a = dataobj;
      let b = dataobj;

      function datafun() {
        return {
          counter: 1,
        };
      }
      // 只要运行一次函数,就会创建一个全新的数据,互不影响
      let x = datafun();
      let y = datafun();
    </script>

3.2.3、创建组件对象的简写方式

创建组件对象也有简写形式:Vue.extend() 可以省略。直接写:{}

 <body>
    <div id="app">
      <h1>{{msg}}</h1>
      <!-- 3. 使用组件 -->
      <userlogin></userlogin>
    </div>

    <script>
      // 1. 创建组件
      /* const userLoginComponent = Vue.extend({
            template : `
            <div>
                <h3>用户登录</h3>
                <form @submit.prevent="login">
                    账号:<input type="text" v-model="username"> <br><br>
                    密码:<input type="password" v-model="password"> <br><br>
                    <button>登录</button>
                </form>
            </div>
            `,
            data(){
                return {
                    username : '',
                    password : ''
                }
            },
            methods: {
                login(){
                    alert(this.username + "," + this.password)
                }
            },
        }) */
      // 底层会在局部或全局注册组件时,自动调用Vue.extend()
      const userLoginComponent = {
        template: `
            <div>
                <h3>用户登录</h3>
                <form @submit.prevent="login">
                    账号:<input type="text" v-model="username"> <br><br>
                    密码:<input type="password" v-model="password"> <br><br>
                    <button>登录</button>
                </form>
            </div>
            `,
        data() {
          return {
            username: "",
            password: "",
          };
        },
        methods: {
          login() {
            alert(this.username + "," + this.password);
          },
        },
      };

      // Vue实例
      const vm = new Vue({
        el: "#app",
        data: {
          msg: "第二个用户登录组件",
        },
        // 2. 注册组件(局部注册)
        components: {
          userlogin: userLoginComponent,
        },
      });
    </script>
  </body>

3.2.4、组件的全局注册

  <body>
    <!-- 
        组件的使用分为三步:
            第一步:创建组件
                Vue.extend({该配置项和new Vue的配置项几乎相同,略有差别})。
            第二步:注册组件
                局部注册:
                    在配置项当中使用components,语法格式:
                        components : {
                            组件的名字 : 组件对象
                        }
                全局注册:
                    Vue.component('组件的名字', 组件对象)
            第三步:使用组件 
      -->
    <div id="app">
      <h1>{{msg}}</h1>
      <!-- 3. 使用组件 -->
      <userlogin></userlogin>
    </div>
    <hr />

    <div id="app2">
      <userlogin></userlogin>
    </div>

    <script>
      const userLoginComponent = {
        template: `
            <div>
                <h3>用户登录</h3>
                <form @submit.prevent="login">
                    账号:<input type="text" v-model="username"> <br><br>
                    密码:<input type="password" v-model="password"> <br><br>
                    <button>登录</button>
                </form>
            </div>
            `,
        data() {
          return {
            username: "",
            password: "",
          };
        },
        methods: {
          login() {
            alert(this.username + "," + this.password);
          },
        },
      };

      // 全局注册
      Vue.component("userlogin", userLoginComponent);

      // 第2个vue实例
      const vm2 = new Vue({
        el: "#app2",
      });

      // Vue实例
      const vm = new Vue({
        el: "#app",
        data: {
          msg: "全局注册组件",
        },
        // 注册组件(局部注册)
        // components: {
        //   userlogin : userLoginComponent
        // },
      });
    </script>
  </body>

3.2.5、组件的命名细节

注册组件细节:

1. 在Vue当中是可以使用自闭合标签的,如果组件需要多次使用,前提必须在脚手架环境中使用。

2. 在创建组件的时候Vue.extend()可以省略,但是底层实际上还是会调用的,在注册组件的时候会调用。

3. 组件的名字

(1):全部小写

(2):首字母大写,后面都是小写

(3):kebab-case命名法(串式命名法。例如:user-login)

(4):CamelCase命名法(驼峰式命名法。例如:UserLogin),

但是这种方式只允许在脚手架环境中使用。

(5)不要使用HTML内置的标签名作为组件的名字。例如:header,main,footer

(6)在创建组件的时候,通过配置项配置一个name,这个name不是组件的名字, 是设置Vue开发者工具中显示的组件的名字。

  <body>
    <div id="app">
      <h1>{{msg}}</h1>
      <!-- 3. 使用组件 -->
      <hello-world></hello-world>
      <hello-world />
      <!-- 使用多个的时候,会报错 -->
      <!-- <hello-world />
      <hello-world /> -->
    </div>

    <script>
      // 1、创建组件
      // const hello = {
      //   template: `<h1> helloworld </h1>`,
      // };
      // 2、全局注册组件
      // Vue.component("hello-world", hello);

      // 注册的时候,同时创建组件
      Vue.component("hello-world", {
        name: "hw",
        template: `<h1> HelloWorld </h1>`,
      });

      // Vue实例
      const vm = new Vue({
        el: "#app",
        data: {
          msg: "组件注册注意点",
        },
      });
    </script>
  </body>

3.3、组件的嵌套

哪里要使用,就到哪里去注册,去使用

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>组件嵌套</title>
    <script src="../js/vue.js"></script>
  </head>
  <body>
    <div id="root">
      <app></app>
    </div>
    <script>
      //4创建child组件
      const child = {
        template: `
         <h3>child组件</h3>
        `,
      };

      //3创建girl组件
      const girl = {
        template: `
         <h2>girl组件</h2>
        `,
      };

      //2 创建son组件
      const son = {
        template: `
       <div>
          <h2>son组件</h2>
           <child />
        </div>
        `,
        components: {
          child,
        },
      };

      //1、创建app组件,并注册son组件和girl组件
      const app = {
        template: `
         <div>
           <h1>app组件</h1>
           <girl />
           <son />
          </div>
        `,
        components: {
          girl,
          son,
        },
      };
      // 创建vm,并注册app组件
      const vm = new Vue({
        el: "#root",
        // 1.3 使用app组件
        //1.2、 注册app组件
        components: {
          app,
        },
      });
    </script>
  </body>
</html>

3.4、VueComponent & Vue

3.4.1、 this

new Vue({})配置项中的this就是:Vue实例(vm)

Vue.extend({})配置项中的this就是:VueComponent实例(vc

打开vm和vc你会发现,它们拥有大量相同的属性。例如:生命周期钩子、methods、watch等。

  <body>
    <div id="app">
      <h1>{{msg}}</h1>
      <user></user>
    </div>
    <script>
      // 创建组件
      const user = Vue.extend({
        template: `
            <div>
                <h1>user组件</h1>
            </div>
            `,
        mounted() {
          // user是什么呢????是一个全新的构造函数 VueComponent构造函数。
          // this是VueComponent实例
          console.log('vc', this)
        },
      });

      // vm
      const vm = new Vue({
        el: "#app",
        data: {
          msg: "vm与vc",
        },
        components: {
          user,
        },
        mounted() {
          // this是Vue实例
          console.log("vm", this);
        },
      });
    </script>
  </body>

3.4.2 vm === vc ???

只能说差不多一样,不是完全相等。

例如:

vm上有el,vc上没有。

另外data也是不一样的。vc的data必须是一个函数。 

只能这么说:vm上有的vc上不一定有,vc上有的vm上一定有。

3.4.3 通过vc可以访问Vue原型对象上的属性

通过vc可以访问Vue原型对象上的属性:

为什么要这么设计?代码复用。Vue原型对象上有很多方法,例如:$mount(),对于组件VueComponent来说就不需要再额外提供了,直接使用vc调用$mount(),代码得到了复用。

Vue框架是如何实现以上机制的呢?

VueComponent.prototype.__proto__ = Vue.prototype

1、回顾原型对象
  <script>
      // prototype  __proto__

      // 构造函数(函数本身又是一种类型,代表Vip类型)
      function Vip() {}

      // Vip类型/Vip构造函数,有一个 prototype 属性。
      // 这个prototype属性可以称为:显式的原型属性。
      // 通过这个显式的原型属性可以获取:原型对象

      // 获取Vip的原型对象
      let x = Vip.prototype;

      // 通过Vip可以创建实例
      let a = new Vip();
      // 对于实例来说,都有一个隐式的原型属性: __proto__
      // 注意:显式的(建议程序员使用的)。隐式的(不建议程序员使用的。)
      
      // 这种方式也可以获取到Vip的原型对象
      let y = a.__proto__;

      // 原型对象只有一个,其实原型对象都是共享的。
      console.log(x === y); // true

      // 作用:
      // 在给“Vip的原型对象”扩展属性
      Vip.prototype.counter = 1000;

      // 通过a实例可以访问这个扩展的counter属性吗?可以访问。为什么?原理是啥?
      // 访问原理:首先去a实例上找counter属性,如果a实例上没有counter属性的话,
      //会沿着__proto__这个原型对象去找。
      
      // 下面代码看起来表面上是a上有一个counter属性,实际上不是a实例上的属性,是a实例对应的原型对象上的属性counter。
      console.log(a.counter);
      //console.log(a.__proto__.counter)
    </script>

2、底层实现

VueComponent.prototype.__proto__ = Vue.prototype

  <body>
    <div id="app">
      <h1>{{msg}}</h1>
      <user></user>
    </div>
    <script>
      // 创建组件
      const user = Vue.extend({
        template: `
            <div>
                <h1>user组件</h1>
            </div>
            `,
        mounted() {
          // this是VueComponent实例
          // user是什么呢????是一个全新的构造函数 VueComponent构造函数。
          // 为什么要这样设计?为了代码复用。
          // 底层实现原理:
          // VueComponent.prototype.__proto__ = Vue.prototype
          console.log("vc.counter", this.counter);
        },
      });
      // vm
      const vm = new Vue({
        el: "#app",
        data: {
          msg: "vm与vc",
        },
        components: {
          user,
        },
        mounted() {
          // this是Vue实例
          console.log("vm", this);
        },
      });

      // 这个不是给Vue扩展counter属性。
      // 这个是给“Vue的原型对象”扩展一个counter属性。
      Vue.prototype.counter = 1000;
      console.log("vm.counter", vm.counter);
      // 本质上是这样的:
      console.log("vm.counter", vm.__proto__.counter);
      console.log("user.prototype.__proto__ === Vue.prototype", user.prototype.__proto__ === Vue.prototype);
    </script>
  </body>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值