前端|Web基础_Vue组件化开发

2021/07/28 前端 共 8675 字,约 25 分钟

Vue

1. 组件化开发

1.1 基本使用过程

  • 注册组件的基本步骤:
    • 创建组件
    • 注册组件
    • 使用组件

  • Vue.extend():
    • 调用Vue.extend()创建的是一个组件构造器。
    • 通常在创建组件构造器时,传入template代表我们自定义组件的模板
    • 改模板就是在使用到组件的地方,要显示的HTML代码
  • Vue.component():
    • 调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称
    • 所以需要传递两个参数:1、注册组件的标签名 2、组件构造器
  • 组件必须挂载在某个Vue实例下。否则他不会生效

Alt Text

<div id="app">
  <!-- 3.使用组件 -->
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
</div>
<script src="../js/vue.js"></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>

1.2 全局组件和局部组件

  • 全局组件:在Vue实例外注册,可以在多个Vue的实例下使用
  • 局部组件:在Vue实例内注册,可以在其Vue的实例下使用 ```html
### 1.3 父组件和子组件

```html
<div id="app">
  <cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<script>
  //1. 创建第一个组件
  const cpnC1 = Vue.extend({
    template: `
      <div>
        <h2>我是标题1</h2>
        <p>我是内容1</p>
      </div>
    `
  })

  //2. 创建第二个组件
  const cpnC2 = Vue.extend({
    template: `
      <div>
        <h2>我是标题2</h2>
        <p>我是内容2</p>
        <cpn1></cpn1>
      </div>`,
    components:{
      cpn1:cpnC1
    }
  })

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    },
    components:{
      cpn2:cpnC2
    }
  })
</script>

1.4 注册组件的语法糖写法

  • 省去Vue.extend() ```html
![Alt Text](/images/posts/3b1e41b795814644b85616fbe0e266d0.png)
### 1.5 组件模板抽离
- script标签
- template标签
```html
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<!--1. script标签,注意:类型必须是text/x-template-->
<script type="text/x-template" id="cpn">
  <div>
    <h2>我是标题2</h2>
    <p>我是内容2</p>
  </div>
</script>
<!--2.template标签-->
<template id="cpn1">
  <div>
    <h2>我是标题2</h2>
    <p>我是内容2</p>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>

  //1.注册一个组件
  Vue.component('cpn',{
    template: '#cpn1'
  })

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    }
  })
</script>

1.6 组件中的data

<div id="app">
  <cpn></cpn>
</div>
<template id="cpn">
  <div>
    <h2></h2>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  Vue.component('cpn',{
    template: '#cpn',
    data(){
      return{
        counter:0
      }
    },
    methods:{
      increment(){
        this.counter++;
      },
      decrement(){
        this.counter--;
      }
    }
  })
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    }
  })
</script>

1.7 父子组件通信

父传子

  • 方法
    • 通过props向子组件传递数据
    • 通过事件向父组件发送消息 Alt Text
  • Vue实例和子组件的通信 和 父组件和子组件的通信过程是一样的
props
  • 不要用驼峰标识 v-bind无法识别,如必须使用:c-info="info" 组件内用驼峰cInfo
  • 在组件中,使用选项props来声明需要从父级接收到的数据。
  • props的值有两种方式:
    • 方式一:字符串数组,数组中的字符串就是传递时的名称
    • 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等

      props数据验证

  • 支持的类型
    • String
    • Number
    • Boolean
    • Array
    • Object
    • Date
    • Function
    • Symbol
<div id="app">
  <cpn :cmovies="movies" :cmessage="message"></cpn>
</div>
<template id="cpn">
  <div>
    <ul>
      <li v-for="item in cmovies"></li>
    </ul>
    <h2></h2>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  //父传子 props
  const cpn = {
    template: '#cpn',
    // props: ['cmovies','cmessage'],
    props:{
      //1.类型限制
      // cmovies: Array,
      // cmessage: String,

      //2.提供一些默认值
      cmessage: {
        type: String, //类型
        default:'aaaaa',  //默认值
        required: true
      },
      //类型是对象或者数组时,默认值必须是一个函数
      cmovies: {
        type:Array,
        default() {
          return []
        }
      }
    },
    data(){
      return{}
    },
  }

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!',
      movies:['海王','海贼王','海尔兄弟']
    },
    components:{
      cpn,
    }
  })
</script>

子传父

自定义事件

  • $emit ```html
<cpn @item-click="cpnClick"></cpn>
#### 父子组件通信案例

```html
<div id="app">
  <cpn :number1="num1"
       :number2="num2"
       @num1change="num1change"
       @num2change="num2change"></cpn>
</div>

<template id="cpn">
  <div>
    <h2>props:</h2>
    <h2>data:</h2>
<!--    <input type="text" v-model="dnumber1">-->
    <input type="text" :value="dnumber1" @input="num1Input">
    <h2>props:</h2>
    <h2>data:</h2>
<!--    <input type="text" v-model="dnumber2">-->
    <input type="text" :value="dnumber2" @input="num2Input">
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!',
      num1:1,
      num2:0
    },
    methods: {
      num1change(value){
        this.num1=parseInt(value);
      },
      num2change(value){
        this.num2=parseInt(value);
      }
    },
    components:{
      cpn:{
        template:'#cpn',
        props:{
          number1:Number,
          number2:Number
        },
        data(){
          return {
            dnumber1:this.number1,
            dnumber2:this.number2,
          }
        },
        methods:{
          num1Input(event){
            this.dnumber1=event.target.value;
            this.$emit('num1change', this.dnumber1);

            this.dnumber2 = this.dnumber1*100;
            this.$emit('num2change',this.dnumber2);
          },
          num2Input(event){
            this.dnumber2=event.target.value;
            this.$emit('num2change', this.dnumber2);

            this.dnumber1 = this.dnumber2/100;
            this.$emit('num1change',this.dnumber1)
          },
        }
      }
    },

  })
</script>

watch监听改变

 watch:{
          dnumber1(newValue){
            this.dnumber2 =  newValue*100;
            this.$emit('num1change', newValue);
          },
          dnumber2(newValue){
            this.dnumber1 =  newValue*100;
            this.$emit('num2change', newValue);
          }
        },

父子组件的访问方式: $children

  • 父组件访问子组件:使用$children$refs(引用)
  • 子组件访问父组件:使用$parent
父访问子
<div id="app">
  <cpn></cpn>
  <cpn></cpn>
  <cpn ref="aaa"></cpn>
  <button @click="btnClick">按钮</button>
</div>
<template id="cpn">
  <div>我是子组件</div>
</template>
<script src="../js/vue.js"></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();
        // }

        //2.$refs
        console.log(this.$refs);

      }
    },
    components:{
      cpn:{
        template:'#cpn',
        data() {
          return{
            name: '我是子组件的name'
          }
        },
        methods:{
          showMessage(){
            console.log('showMessage');
          }
        }
      }
    }
  })
</script>
子访问父
<div id="app">
  <cpn></cpn>
</div>
<template id="cpn">
  <div>
    <h2>我是cpn组件</h2>
    <ccpn></ccpn>
  </div>
</template>
<template id="ccpn">
  <div>
    <h2>我是子组件</h2>
    <button @click="btnClick">按钮</button>
  </div>
</template>
<script src="../js/vue.js"></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.访问父组件
                console.log(this.$parent);
                console.log(this.$parent.name);

                //2.访问根组件$root
                console.log(this.$root);
                console.log(this.$root.message);
              }
            },
          }
        }
      }
    }
  })
</script>

2. 组件化高级

2.1 slot 插槽

2.1.1 基本使用

  1. 插槽的基本使用<slot></slot>
  2. 插槽的默认值<slot>button</slot>
  3. 多个值同时放入到组件中,则一起组我诶替换元素 ```html
哈哈哈 哈哈哈
我是div元素

我是p元素

#### 2.1.2 具名插槽
- 多个插槽,区分通过添加`name`
```html
<div id="app">
  <cpn>
    <button slot="left">返回</button>
    <span slot="center">标题</span>
  </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="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    },
    components:{
      cpn:{
        template:'#cpn'
      }
    }
  })
</script>

2.2 编译作用域

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

2.3 作用域插槽

<div id="app">
  <cpn></cpn>
  <cpn>
    <!--<span v-for="item in pLanguages"></span>-->
    <template slot-scope="slot">
<!--      <span v-for="item in slot.data"> - </span>-->
      <span></span>
    </template>
  </cpn>

  <cpn>
    <!--<span v-for="item in pLanguages"></span>-->
    <template slot-scope="slot">
<!--      <span v-for="item in slot.data"> * </span>-->
      <span></span>
    </template>
  </cpn>
</div>
<template id="cpn">
  <div>
    <slot :data="pLanguages">
      <ul>
        <li v-for="item in pLanguages"></li>
      </ul>
    </slot>
  </div>
</template>
<script src="../js/vue.js"></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>

Alt Text

文档信息

Search

    Table of Contents