vue组件

组件化

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>title</title>
</head>

<body>
  <!-- 组件化:
  如果我们将一个页面中所有的逻辑处理全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及拓展

  我们将一个完整的页面分成很多个组件。每个组件都用于事件页面的一个功能块。而每一个组件又可以进行细分

  Vue组件化思想:
  它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用
  任何的应用都会被抽象成一颗组件树

  组件使用三个步骤:
  创建组件构造器
  注册组件
  使用组件
  -->
  <div id="app">
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
  </div>

  <script src="../js/vue.js"></script>
  <script>
    // 1.创建组件的构造器对象
    // 传入template代表我们自定义组件模板,垓模板就是使用到组件的地方要显示的html代码
    const cpnC = Vue.extend({
      template: `
        <div>
          <h2>我是标题</h2>
          <p>我是内容,哈哈哈哈哈</p>
          <p>我是内容,哈哈哈哈哈</p>
        </div>`
    });
    // 2.注册组件
    // 将构造器注册为一个组件,并且给他起一个组件标签名称   (注册组件的标签名,组件构造器)

    // 这里注册的是全局组件
    // Vue.component('my-cpn', cpnC);

    // 组件必须挂载在vue实例下,否则不会生效
    const app = new Vue({
      el: '#app',
      data: {
      },
      components: {
        // 局部组件 这里是因为中间有一个‘-’,所以使用引号将其引起来
        'my-cpn': cpnC
      }
    })
  </script>
</body>

</html>

父组件和子组件

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>title</title>
</head>

<body>
  <div id="app">
    <cpn2></cpn2>
    <!-- <cpn1></cpn1> -->
    <cpn3></cpn3>
    <cpn4></cpn4>
    <cpn5></cpn5>
  </div>

  <template id="cpn5">
    <div>
      <h2>我是标题5</h2>
      <p>我是内容,哈哈哈哈哈</p>
      <p>我是内容,哈哈哈哈哈</p>
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>
    // 子组件
    const cpnC1 = Vue.extend({
      template: `
        <div>
          <h2>我是标题1</h2>
          <p>我是内容,哈哈哈哈哈</p>
          <p>我是内容,哈哈哈哈哈</p>
        </div>`
    });

    // 语法糖 全局组件
    Vue.component('cpn3', {
      template: `
        <div>
          <h2>我是标题3</h2>
          <p>我是内容,哈哈哈哈哈</p>
          <p>我是内容,哈哈哈哈哈</p>
        </div>`
    })
    // 将模板提出去
    Vue.component('cpn5', {
      template: '#cpn5'
    })

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

    // root组件
    const app = new Vue({
      el: '#app',
      data: {
      },
      components: {
        cpn2: cpnC2,
        //要想直接使用cpn1必须再注册
        cpn1: cpnC1,
        cpn4: {
          template: `
            <div>
              <h2>我是标题4</h2>
              <p>我是内容,哈哈哈哈哈</p>
              <p>我是内容,哈哈哈哈哈</p>
            </div>`
        }
      }
    })
  </script>
</body>

</html>

组件通信-父传子

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>title</title>
</head>

<body>
  <div id="app">
    <cpn5></cpn5>
    <cpn :cmovies="movies" :cmessage="message"></cpn>
    <cpn :cmovies="movies"></cpn>
    <!-- 当前版本props不支持驼峰命名,需要使用横线  cInfo   c-info -->
    <cpn :c-info="info"></cpn>
  </div>

  <template id="cpn5">
    <div>
      <h2>{{title}}</h2>
      <p>我是内容,哈哈哈哈哈</p>
      <p>我是内容,哈哈哈哈哈</p>
    </div>
  </template>

  <template id="cpn">
    <div>
      <h2>{{cmessage}}</h2>
      <h2>{{cmovies}}</h2>
      <h2>{{cInfo}}</h2>
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>

    // 组件对象里面有一个data属性,只是这个data必须是一个方法,而这个方法返回一个对象,对象内部保存着数据
    // 这样返回一个对象,保证了每次调用组件都是不同的对象,如果data是属性的话,就相当于返回的同一内存地址,是同一对象
    Vue.component('cpn5', {
      template: '#cpn5',
      data() {
        return {
          title: '我是标题5'
        }
      }
    })

    // 通过props向子组件传递数据
    // 通过事件向父组件发送消息
    const cpn = {
      template: '#cpn',
      // 数组写法,引号里的是变量,不是字符串
      // props: ['cmovies','cmessage']
      // 对象写法,可以指定属性值类型
      props: {
        // 支持的类型:String,Number,Boolean,Array,Object,Date,Function,Symbol
        // cmovies: Array,
        // cmessage: String
        // 提供一些默认值
        cmessage: {
          // 设置类型
          type: String,
          // 设置默认值
          default: 'aaaaa',
          // 是否必传属性
          required: false
        },
        cmovies: {
          type: Array,
          // 类型是数组或者是对象时,默认值必须是一个函数
          default() {
            return [];
          }
        },
        cInfo: {
          type: Object,
          default() {
            return {};
          }
        }
      }
    }
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊',
        movies: ['海王', '海贼王', '海尔兄弟'],
        info: {
          name: 'jxd',
          age: 23,
          height: 170
        }
      },
      components: {
        cpn
      }
    })
  </script>
</body>

</html>

组件通信-子传父

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>title</title>
</head>

<body>
  <!-- 父组件模板 -->
  <div id="app">
    <!-- 父组件可以监听子组件发射的事件 如果调用方法不传值,就是默认子组件发射的参数 -->
    <cpn @itemclick="cpnClick"></cpn>
  </div>

  <!-- 子组件模板 -->
  <template id="cpn">
    <div>
      <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>

    const cpn = {
      template: '#cpn',
      data() {
        return {
          categories: [
            { id: 'aaa', name: '热门推荐' },
            { id: 'bbb', name: '手机数码' },
            { id: 'ccc', name: '家用电器' },
            { id: 'ddd', name: '电脑办公' },
          ]
        }
      },
      methods: {
        btnClick(item) {
          // console.log(item);
          // 向父组件发射一个事件 —— 自定义事件,事件命,参数
          this.$emit('itemclick', item);
        }
      }
    }

    const app = new Vue({
      el: '#app',
      data: {
      },
      components: {
        cpn
      },
      methods:{
        cpnClick(item){
          console.log(item);
        }
      }
    })
  </script>
</body>

</html>

父子组件双向绑定

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>title</title>
</head>

<body>
  <div id="app">
    <cpn :number="num" @numchange="numChange" />
  </div>

  <template id="cpn">
    <div>
      <h2>props:{{number}}</h2>
      <h2>data:{{dnumber}}</h2>
      <!-- <input type="text" v-model="dnumber"> -->
      <input type="text" :value="dnumber" @input="numInput">
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        num: 1
      },
      methods: {
        numChange(value) {
          // 字符串转数字
          // this.num = Number(value);
          this.num = parseInt(value);
        }
      },
      components: {
        cpn: {
          template: '#cpn',
          props: {
            number: Number
          },
          data() {
            return {
              dnumber: this.number
            }
          },
          methods: {
            numInput(event) {
              // 将input中的value赋值到dnumber中
              this.dnumber = event.target.value;
              // 为了让父组件可以修改值,发生一个事件
              this.$emit('numchange', this.dnumber);
            }
          },
          // 监听可以监听props,data中的值
          watch:{
            
          }
        }
      }
    })
  </script>
</body>

</html>

组件访问-父访问子

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>title</title>
</head>

<body>
  <div id="app">
    <div>
      <cpn></cpn>
      <cpn></cpn>
      <cpn ref="aaa"></cpn>
      <button @click="btnclick()">按钮</button>
    </div>
  </div>

  <template id="cpn">
    <div>
      {{name}}
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
      },
      methods: {
        btnclick() {
          // this.$children 获取子组件对象,是一个数组  用的比较少,因为数组通过下标去取不好
          /* for (let c of this.$children) {
            console.log(c);
            c.showMessage();
            console.log(c.name);
          } */
          // this.$refs 是对象 默认是一个空对象,需要在组件标签上添加 ref属性  如:ref="aaa"
          console.log(this.$refs.aaa.name);
        }
      },
      components: {
        cpn: {
          template: '#cpn',
          data() {
            return {
              name: '我是一个子组件'
            }
          },
          methods: {
            showMessage() {
              console.log('showMessage');
            }
          }
        }
      }
    })
  </script>
</body>

</html>

组件访问-子访问父

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>title</title>
</head>

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

  <template id="cpn">
    <div>
      <h2>{{name}}</h2>
      <button @click="btnclick">按钮</button>
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        name: 'jxd'
      },
      components: {
        cpn: {
          template: '#cpn',
          data() {
            return {
              name: '我是子组件'
            }
          },
          methods: {
            btnclick() {
              // 1.访问父组件 $parent
              console.log(this.$parent);
              console.log(this.$parent.name);

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

</html>

组件插槽

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>title</title>
</head>

<body>
  <div id="app">
    <cpn><span>不使用插槽默认值</span></cpn>
    <cpn></cpn>
    <cpn></cpn>
    <cpn></cpn>


    <!-- 具名插槽 只会替换有名字的 -->
    <cpn1><span slot="center">标题</span></cpn1>
  </div>

  <!-- 组件插槽:
    为了让我们封装的组件更加具有拓展性
    让使用者可以决定组件内部的一些内容到底展示什么
   -->

  <template id="cpn">
    <div>
      <h2>我是组件</h2>
      <p>我是组件,哈哈哈哈</p>
      <!-- 插槽可以传入默认值 如果有指定,就显示指定的 -->
      <slot><button>按钮</button></slot>
    </div>
  </template>

  <!-- 具名插槽 -->
  <template id="cpn1">
    <div>
      <slot name="left"><span>左边</span></slot>
      <slot name="center"><span>中间</span></slot>
      <slot me="right"><span>右边</span></slot>
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
      },
      components: {
        cpn: {
          template: '#cpn'
        },
        cpn1: {
          template: '#cpn1'
        }
      }
    })
  </script>
</body>

</html>

编译作用域

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>title</title>
</head>

<body>
  <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: {
        isShow: true
      },
      components: {
        cpn: {
          template: '#cpn',
          data() {
            return {
              isShow: false
            }
          }
        }
      }
    })
  </script>
</body>

</html>

作用域插槽

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>title</title>
</head>

<body>
  <div id="app">
    <cpn></cpn>
    <cpn>
      <!-- 目的获取子组件的pLanguages -->
      <!-- vue 2.5.x 一下需要使用templatek获取  :data中的值 -->
      <template slot-scope="slot">
        <!-- <span v-for="item in slot.data">{{item}} - </span> -->
        <span>{{slot.data.join(' - ')}}</span>
      </template>
    </cpn>
  </div>



  <!-- 父组件替换插槽的标签,但是内容由子组件来提供 -->

  <template id="cpn">
    <div>
      <!-- 这里的 :data 可以随便取名  如 :abc   使用的时候就是slot.abc  -->
      <slot :data="pLanguages">
        <ul>
          <li v-for="item in pLanguages">{{item}}</li>
        </ul>
      </slot>
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
      },
      components: {
        cpn: {
          template: '#cpn',
          data() {
            return {
              pLanguages: ['JavaScript', 'C++', 'Java', 'C#', 'Python', 'Go']
            }
          }
        }
      }
    })
  </script>
</body>

</html>
上一篇:Vue 组件化开发


下一篇:leecode-找出其中不含有重复字符的 最长子串 的长度