Vue组件化

Vue组件化

1.1、Vue组件注册

​ 注册vue组件的步骤:创建组件构建器

​ 注册组件

​ 使用组件。

<!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>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <my-cpn></my-cpn>
    </div>
    <script>
        //创建组件构造器  有语法糖简化写法
         const cpn = Vue.extend({
             template:`<div>
                        <h1>我是标题</h1>
                        <p>我是内容</p> 
                      </div>`
         });
        //注册组件
        Vue.component("my-cpn",cpn);
        let app = new Vue({
            el: "#app",
            data: {
                mess: "您好"
            }
        });
    </script>
</body>

</html>

总结:

​ 创建组件的基本步骤: 创建组件构造器、注册组件以及使用组件。

​ 语法:创建组件构造器:

​ const c = Vue.extend({

​ template:‘布局内容’

​ });

​ 注册组件: Vue.component(“标签名称【自定义】”,c【构造器名称】);

1.2、局部组件和全局组件

​ 代码如下:

<!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>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <my-cpn></my-cpn>
    </div>
    <div id="app1">
        <cpn></cpn> 
    </div>
    <script>
        /*全局组件   全局组件就意味着可以在多个Vue实例中使用*/
        //创建组件构造器   
        const comApp = Vue.extend({
            template: `<div>
                        <h1>我是标题</h1>
                        <p>全局组件的使用</p> 
                      </div>`
        });
        //注册组件 
        Vue.component("my-cpn", comApp);
        let app = new Vue({
            el: "#app",
            data: {
                mess: "您好"
            }
        });
        /*全局组件   全局组件就意味着可以在多个Vue实例中使用*/

        /*局部组件  再项目的开发中使用最多的还是局部组件  */
        const comApp1 = Vue.extend({
            template: `<div>
                        <h1>我是标题</h1>
                        <p>局部组件的使用</p> 
                      </div>`
        });
        let app1 = new Vue({
            el: "#app1", 
            components: {
                //cpn 就是組件的标签名   comApp1:是组件构造器的名称
                cpn: comApp1
            }
        });
       /*局部组件  */
    </script>
</body>

</html>

总结:

​ 全局组件是可以在多个Vue实例中进行使用,但是在实际的开发中使用全局组件比较少。

​ 局部组件是在单个的创建的Vue实例使用,需要单独创建组件构造器,但是在实际的开发过程使用局部组件比较多。

1.3 、父组件与子组件

代码如下:

<!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>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body> 
    <div id="app1">
        <comapp2></comapp2> 
    </div>
    <script> 

        /* 子组件  */
        const comApp1 = Vue.extend({
            template: `<div>
                        <h1>我是标题</h1>
                        <p>子组件的使用</p> 
                      </div>`
        });
        /*父组件 */
        const comApp2 = Vue.extend({
            template: `<div>
                        <h1>我是标题</h1>
                        <p>父组件的使用</p> 
                        <comapp1></comapp1>
                      </div> 
                      `,
           components:{
               comapp1:comApp1
           }
        });
        let app1 = new Vue({
            el: "#app1", 
            components: {
                //cpn 就是組件的标签名   comApp1:是组件构造器的名称
                comapp2: comApp2
            }
        });
       /*  */
    </script>
</body>

</html>

总结:

每个组件构造器中都会有一个 components属性,用来挂载 子组件的构造器。

语法如下:

​ const c = Vue.extend ({

​ template:``,

​ components:{

​ 标签名:子组件构造器名称 [标签名为自定义]

​ }

​ });

而父组件则挂载到根组件上面,也就是创建的Vue实例。

需要注意:子组件的标签必须放到父组件的div里面,要不然会报错。

1.4、注册组件的语法糖写法

代码如下:

<!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>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <my-cpn></my-cpn>
    </div>
    <div id="app1">
        <cpn></cpn>
    </div>
    <script>
        /*全局组件  语法糖写法*/

        //注册组件 
        Vue.component("my-cpn", {
            template: `<div>
                        <h1>我是标题</h1>
                        <p>全局组件的使用</p> 
                      </div>`
        });
        let app = new Vue({
            el: "#app",
            data: {
                mess: "您好"
            }
        });
        /*全局组件  语法糖写法*/

        /*局部组件  语法糖写法  */

        let app1 = new Vue({
            el: "#app1",
            components: {
                //cpn 就是組件的标签名   comApp1:是组件构造器的名称
                cpn: {
                    template: `<div>
                        <h1>我是标题</h1>
                        <p>局部组件的使用</p> 
                      </div>`
                }
            }
        });
       /*局部组件 语法糖写法  */
    </script>
</body>

</html>

总结:看以上代码。

1.5、组件模板的分离写法

代码如下:

<!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>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app1">
        <cpn></cpn>
    </div>
    <script type="text/x-template" id ="con">
        <div>
            <h1>组件抽离第一种写法</h1>
            <p>局部组件的使用</p> 
          </div>
    </script>
    <template id ="con">
        <div>
            <h1>组件抽离二种写法</h1>
            <p>局部组件的使用</p> 
          </div>
    </template>
    <script>
        /*局部组件  语法糖写法  */
        let app1 = new Vue({
            el: "#app1",
            components: {
                //cpn 就是組件的标签名   comApp1:是组件构造器的名称
                cpn: {
                    template:'#con'
                }
            }
        });
       /*局部组件 语法糖写法  */
    </script>
</body>

</html>
<!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>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<!--另一种写法-->
<body>
    <div id="app">
      <par></pars>
       
    </div>
    <template id="parent">
        <div>
            父组件
           <ch></ch>
        </div>
    </template>
    <template id="child">
        <div>子组件</div>
    </template>
    <script>
        let app = new Vue({
            el: "#app",
            components: {
                par: {
                    template: "#parent",
                    components:{
                        ch:{
                            template: "#child",
                        }
                    } 
                }
            }
        });
    </script>
</body>

</html>

总结:看以上代码。

1.6、为什么组件使用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>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app1">
        <cpn></cpn> 
    </div> 
    <template id="con">
        <div>
            当前的数字:{{num}}<br>
            <button @click="reduce">-</button>
            <button @click="add">+</button>
        </div>
    </template>
    <script> 
        let app1 = new Vue({
            el: "#app1",
            components: {
                cpn: {
                    template: '#con',
                    data() {
                        return {
                            num: 0
                        }
                    },
                    methods: {
                        reduce() {
                            this.num--;
                        },
                        add() {
                            this.num++;
                        }
                    }
                }
            }
        }); 
    </script>
</body> 
</html>

总结:

组件多次调用,必须用data()方法,返回一个新的对象,而避免多次调用触发事件值会发生连锁反应。

1.7、父组件与子组件的通信

代码如下:

<!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>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <par :clist="list" :cmess ="mess">
            </pars>

    </div>
    <template id="parent">
        <div>
            <ul>
                <li v-for="item in clist">{{item}}</li>
            </ul>
            {{cmess}}
        </div>
    </template>
    <script>
        const par = {
            template: "#parent",
             //props: ['clist','cmess'] //第一种方式
            //  props:{  //第二种方式
            //     clist:Array,
            //     cmess:String
            //  }
            props:{ //第三种方式
                clist:{
                    type:Array,  //  组件的变量数据类型
                    default(){   //  默认值  但是数组的默认必须是函数
                        return [];
                    },
                    required:true//如果等于true  使用这个变量的时候,必须是clist变量名。
                },
                cmess:{
                    type:String,
                    default:'',
                    required:true
                }
            }
        };
        let app = new Vue({
            el: "#app",
            data: {
                list: ['海王', '七龙珠', '海尔兄弟'],
                mess:"您好"
            },
            components: {
                par
            }
        });
    </script>
</body>

</html>

总结:

父组件与子组件之间的通信有两种方式:

1)、props 属性 父组件向子组件传递

​ props有三种写法:

​ ①、直接变量写到props数组中。请看代码第一种使用方式。

​ ②、将props变成对象,里面的属性也就是要绑定的变量,以键值对的方式:key:变量名 value值为:传递变量的数据类型;详情看代码第二种使用方式。

​ ③、将props里面的变量,变成对象。请看代码第三种使用方式。 【推荐使用第三种】

注意:

​ 定义:定义组件变量的时候,不要使用驼峰标识的方式命名变量。

2)、通过事件从子组件向父组件传递,也就是自定义事件。

1.8、子组件向父组件传值并发送自定义事件

​ 代码如下:

<!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>子组件往父组件传值</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    父组件接收子组件的值:{{mess}} <br><br>
    <com @parentclick="parent"></com>
  </div>
  <template id="temp">
    <div>
      <ul>
        <li v-for="item in list"><button @click="childchangs(item)">{{item}}</button></li>
      </ul>
    </div>
  </template>
  <script>
    const com = {
      template: "#temp",
      data() {
        return {
          list: ['数码产品', '办公耗材', '生活用品']
        }
      },
      methods: {
        childchangs(item) {
          console.log(item);
          //往父组件传递值
          this.$emit('parentclick', item);
        }
      }
    }
    let app = new Vue({
      el: "#app",
      components: {
        com
      },
      data: {
        mess: ''
      },
      methods: {
        parent(item) {
          this.mess = item;
        }
      }
    });
  </script>
</body>

</html>

总结:

​ 子组件往父组件传值,需要借助 this.$emit(‘自定义事件名称’,参数) 往父组件发送一个事件,并在父组件进行监听事件。以上代码可参考。

1.9、子组件往父组件传值,并同步更新父组件上变量的值 经典案例

​ 需求背景:

​ 页面中有两个文本框【子组件】同时还有父组件的两个变量,子组件的两个变量,输入文本后同时更新父组件的变量和子组件的变量。

​ 代码如下:

<!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>子组件往父组件传值</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    父组件vue实例中变量mess1:{{mess1}}<br><br>
    父组件vue实例中变量mess2:{{mess2}}<br><br>
    <con :pmess1="mess1" :pmess2="mess2" @parevent1="parclick1" @parevent2="parclick2"></con>
  </div>
  <template id="temp">
    <div>
      子组件中变量cmess1:{{cmess1}}<br><br>
      子组件中变量cmess2:{{cmess2}}<br><br> 
      <input type="text" name="name1" :value="cmess1" @input="inputChanges1" style="width:100%"></input><br><br>
      <input type="text" name="name2" :value="cmess2" @input="inputChanges2" style="width:100%"></input>
    </div>
  </template>
  <script>
    const con = {
      template: "#temp",
      data() {
        return {
          cmess1: this.pmess1,
          cmess2: this.pmess2
        }
      },
      props: {
        pmess1: {
          type: String,
          default: "",
          required: true
        },
        pmess2: {
          type: String,
          default: "",
          required: true
        }
      },
      methods: {
        //监听input事件
        inputChanges1(event) {
          this.cmess1 = event.target.value;
          //发送自定义事件到父组件中
          this.$emit("parevent1", this.cmess1);
        },
        inputChanges2(event) {
          this.cmess2 = event.target.value;
          //发送自定义事件到父组件中
          this.$emit("parevent2", this.cmess2);
        }
      }
    };
    let app = new Vue({
      el: "#app",
      data: {
        mess1: "hellow word!",
        mess2: "say hi!"
      },
      components: {
        con
      },
      methods: {
        parclick1(value) {
          this.mess1 = value;
        },
        parclick2(value) {
          this.mess2 = value;
        }
      }
    });
  </script>
</body>

</html>

2.0、父子组件的访问方式

代码如下:

<!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>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <cpn  ref ="cpn"></cpn>
    <button @click="parentclick">触发子组件showmessage方法</button>
  </div>
  <template id="temp">
    <div>
      {{cmess}}
    </div>
  </template>
  <script>
    const cpn = {
      template: "#temp",
      data() {
        return {
          cmess: "您好"
        }
      },
      methods: {
        showmessage() {
         console.log("我是子组件中的showmessage函数");
        }
      }
    }
    let app = new Vue({
      el: "#app",
      components: {
        cpn
      },
      methods:{
        parentclick(){
          //第一种方式:在父组件中调用子组件的属性或者函数   [不经常使用]
          // this.$children[0].showmessage();
          // console.log(this.$children[0].cmess) ; 
          // console.log(this.$children); 
          // console.log("我是父组件parentclick函数!");
          //第二种方式  [经常使用]
            console.log(this.$refs.cpn.cmess); 
            console.log(this.$refs.cpn.showmessage()); 
        }
      }
    });
  </script>
</body>

</html>

总结:

​ 如果想用父组件访问子组件就使用:$children 或 r e f s , 实 际 开 发 中 经 常 使 用 refs ,实际开发中经常使用 refs使refs,但是必须在子组件的标签中添加 ref = ‘值’ 属性才能访问到子组件的属性或者函数。

​ 子组件访问父组件就使用:$parent 【不经常使用】

2.1、solt 具名插槽基本使用 【很重要】

代码如下:

<!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>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <cpn><button>按钮</button></cpn>
    <cpn></cpn>
  </div>
  <template id="temp">
    <div>您好
      <div>
        <!-- 也可以在插槽中放入默认值,如果组件没有放入标签,那么会使用默认值 -->
        <slot></slot>
      </div>
    </div>

  </template>
  <script>
    const cpn = {
      template: "#temp"
    };
    let app = new Vue({
      el: "#app",
      data: {
        mess: "您好"
      },
      components: {
        cpn
      }
    });
  </script>
</body>

</html>

总结:

​ 插槽的定义: 抽取共性,保留不同。

​ 1、插槽的基本使用
​ 2、插槽是可以放默认值 ,如果组件标签中没有其他内容那么页面会渲染出插槽中的默认值,如果组件标签中有元素,那么会将插槽中的元素替换掉。

2.2、具名插槽的使用

代码如下:

<!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>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <cpn>
      <span slot="left">左边1</span>
      <span slot="center">中间1</span>
      <span slot="right">右边1</span>
    </cpn>
    <cpn> 
      <span slot="right">标题</span>
    </cpn>
  </div>
  <template id="temp">
    <div>您好
      <div>
        <slot name="left"><button>左边</button></slot>
        <slot name="center"><button>中间</button></slot>
        <slot name="right"> <button>右边</button></slot>
      </div>
    </div>

  </template>
  <script>
    const cpn = {
      template: "#temp"
    };
    let app = new Vue({
      el: "#app",
      data: {
        mess: "您好"
      },
      components: {
        cpn
      }
    });
  </script>
</body>

</html>

总结:

​ 在实际的开发过程中有些部分不是共用的,我们需要将不是共用部分放到指定的位置,就得需要具名插槽。

2.3、作用于插槽的使用

代码如下:

<!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>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <cpn>
      <template slot-scope="slot">
       <span v-for ="item in slot.data">{{item}}****</span>
      </template>
    </cpn>
  </div>
  <template id="cpn">
    <div>
      <slot :data ="list">
        <ul>
          <li v-for="item in list">{{item}}</li>
        </ul>
      </slot> 
    </div>
  </template>


  <script>
    const cpn = {
      template: "#cpn",
      data() {
        return {
          list: ['python', 'C++', 'java', 'C#', 'php', 'Go']
        }
      }
    }
    let app = new Vue({
      el: '#app',
      components: {
        cpn
      }
    });
  </script>
</body>

</html>

总结:

​ 作用域插槽:父组件替换插槽的标签,但是内容由子组件来提供。

​ 在实际的开发中我们需要在组件中将数据以不同的方式展示,比如:横向、纵向,想在父组件中展示,那么我们如何拿到子组件中的数据,

1)需要在子组件模板中 定义一个属性 :data= “子组件变量” [:data 随便命名],然后再父组件中的子组件标签中定义模板 定义引用 slot-scope=“slot” ,然后横向展示数据。

2.4、ES模块化导入导出
代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="AA.js" type="module"></script>
    <script src="BB.js" type="module"></script>

</head>
<body>

</body>
</html>

AA.js

//第一种导出方式  导出对象
let  name = "小明";
let flag = true;
export {
   name,
   flag
}
//第二种导出方式  导出变量
export let  name = "小明";
export let  flag = true;

//第三种导出方式  函数
export  function test (sum1,sum2)
{
   return sum1+sum2;
}
//第四种导出  类
export  class  person {
   run (){
       console.log("导出类");
    }
}
//第五种  export  default   一个模块只有一个default
const  address ="山东省济南市"
export  default address

export  default 函数   
export  default function (){
   return "export  default 函数"
}
//第六种全部导出  加 export
export let name ="再见"

BB.js

/**
 * Created by Mr.Fu on 2021/6/6.
 */
import {name,flag} from './AA.js'
if (flag){
    console.log(name);
}
//导入变量
import name from './AA.js'
console.log(name);
import flag from './AA.js'
console.log(flag);
//导入方法
import  {test} from './AA.js'
console.log(test(20,20));
//导入类
import {person} from './AA.js'
 const  p= new person();
console.log(p.run());
//导入 default
import  add from './AA.js'
console.log(add);
//导入 default 函数
import  add from './AA.js'
console.log(add());
//统一全部导入
import * as demo from './AA.js'
console.log(demo.name);

总结:

​ 第一种

​ 导出对象:

let  name = "小明";
let flag = true;
export {
   name,
   flag
}

​ 导入对象:

import {name,flag} from './AA.js'
if (flag){
    console.log(name);
}

第二种

导出变量:

//第二种导出方式  导出变量
export let  name = "小明";
export let  flag = true;

导入变量:

import name from './AA.js'
console.log(name);
import flag from './AA.js'
console.log(flag);

第三种

导出函数:

//第三种导出方式  函数
export  function test (sum1,sum2)
{
   return sum1+sum2;
}

导入函数:

//导入方法
import  {test} from './AA.js'
console.log(test(20,20));

第四种

导出类:

//第四种导出  类
export  class  person {
   run (){
       console.log("导出类");
    }
}

导入类:

//导入类
import {person} from './AA.js'
 const  p= new person();
console.log(p.run());

第五种 一个模块只有一个default

导出export default:

//第五种  export  default   一个模块只有一个default
const  address ="山东省济南市"
export  default address

export  default 函数   
export  default function (){
   return "export  default 函数"
}

导入export default:

//导入 default
import  add from './AA.js'
console.log(add);
//导入 default 函数
import  add from './AA.js'
console.log(add());

第六种

​ 全部导出:

//第六种全部导出  加 export
export let name ="再见"

​ 全部导入:

//统一全部导入
import * as demo from './AA.js'
console.log(demo.name);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值