VueJs学习笔记2

组件化开发

  组件的基本使用(全局组件)


  <!-- 
  组件的使用分成三个步骤:
    1.创建组件构造器
    2.注册组件
    3.使用组件。
 -->
  <div id="app">
    <!--3.在Vue实例范围内使用组件-->
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
<!-- 如果组件中间没有内容,也可以写成单标签 <my-cpn/> -->
    <div>
      <div>
        <my-cpn></my-cpn>
      </div>
    </div>
  </div>
 
  <my-cpn></my-cpn>
 
  <script src="../js/vue.js"></script>
  <script>
    // 1.创建组件构造器对象  extend() 没有s
    const cpnC = Vue.extend({
      // 自定义组件的模板 使用到组件的地方,要显示的HTML代码
      // *最外需要一个div包裹
      template: `
      <div>
        <h2>我是标题</h2>
        <p>我是内容1</p>
        <p>我是内容2</p>
      </div>`
    })
 
    // 2.注册组件(全局注册) 
    // 需要传递两个参数:
    // 1、注册组件的标签名 (必须加引号)
    // 2、组件构造器
 
    Vue.component('my-cpn', cpnC)
 
 
 
    // 以上两步需要在Vue实例创建之前
 
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊'
      }
    })
  </script>

  全局组件和局部组件

 
<div id="app">
  <cpn></cpn>
  <cpn></cpn>
  <cpn></cpn>
</div>
 
<div id="app2">
  <cpn></cpn>
</div>
 
<script src="../js/vue.js"></script>
<script>
  // 1.创建组件构造器
  const cpnC = Vue.extend({
    template: `
      <div>
        <h2>我是全局组件</h2>
        <p>我是内容,哈哈哈哈啊</p>
      </div>
    `
  })
 
  // 2.注册组件(component注册的是全局组件, 意味着可以在多个Vue的实例下面使用,比如app,和app2都可以使用cpn)
 
  // Vue.component('cpn', cpnC); // '标签名一定要加引号'
 
  // 疑问: 怎么注册的组件才是局部组件了? 挂载在某个实例中
 
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    },
    components: {
      // 使用组件时的标签名:组件构造器
      // 'cpn': cpnC  局部组件的标签名有无引号都可以
      cpn: cpnC
    }
  })
 
  const app2 = new Vue({
    el: '#app2'
  })
</script>

     父组件和子组件

   父子组件正确用法:在 父组件的components注册,在template 中使用子组件标签

 
  <div id="app">
    <cpn2></cpn2>
    <!-- 父子组件错误用法:以子标签的形式在Vue实例中使用 -->
    <!--<cpn1></cpn1>-->
    <!-- 正确写法 在 template 中使用 <cpn1></cpn1> -->
  </div>
 
  <script src="../js/vue.js"></script>
  <script>
    // 1.创建第一个组件构造器(子组件)
    const cpnC1 = Vue.extend({
      template: `
      <div>
        <h2>我是标题1</h2>
        <p>我是内容, 哈哈哈哈</p>
      </div>
    `
    })
 
 
    // 2.创建第二个组件构造器(父组件)
    const cpnC2 = Vue.extend({
      // 2.2 在 template 中使用 <cpn1></cpn1>
      template: `
      <div>
        <h2>我是标题2</h2>
        <p>我是内容, 呵呵呵呵</p>
        <cpn1></cpn1>
      </div>
    `,
      // 2.1 在components注册子组件cpn1
      components: {
        cpn1: cpnC1
      }
    })
 
    // root组件
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊'
      },
      components: {
        cpn2: cpnC2
      }
    })
  </script>

  注册组件语法糖

主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替。

 
  <div id="app">
    <cpn1></cpn1>
    <cpn2></cpn2>
  </div>
 
  <script src="../js/vue.js"></script>
  <script>
    // 主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替
 
    // 1.全局组件注册的语法糖
    // * Vue.component标签名必须加引号
    Vue.component('cpn1', {
      template: `
      <div>
        <h2>我是标题1</h2>
        <p>我是内容, 哈哈哈哈</p>
      </div>
    `
    })
 
    // 2.注册局部组件的语法糖
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊'
      },
      components: {
        'cpn2': {
          template: `
          <div>
            <h2>我是标题2</h2>
            <p>我是内容, 呵呵呵</p>
          </div>
    `
        }
      }
    })
  </script>

  模块的分离写法

 
  <div id="app">
    <cpn></cpn>
    <cpn></cpn>
    <cpn></cpn>
  </div>
 
  <!--1.script标签, 注意:类型必须是text/x-template 然后给它设置一个id -->
  <script type="text/x-template" id="cpn">
    <div>
      <h2>我是标题</h2>
      <p>我是内容,哈哈哈</p>
    </div>
  </script>
 
  <!--2.template标签-->
  <template id="cpn">
    <div>
      <h2>我是标题</h2>
      <p>我是内容,呵呵呵</p>
    </div>
  </template>
 
  <script src="../js/vue.js"></script>
  <script>
    // 1.注册一个全局组件
    Vue.component('cpn', {
      template: '#cpn' // 需要加上选择器
    })
 
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊'
      }
    })
  </script>

组件数据的存放

 
<div id="app">
  <cpn></cpn>
  <cpn></cpn>
  <cpn></cpn>
</div>
 
<template id="cpn">
  <div>
    <h2>{{title}}</h2>
    <p>我是内容,呵呵呵</p>
  </div>
</template>
 
<script src="../js/vue.js"></script>
<script>
 
  // 1.注册一个全局组件
  Vue.component('cpn', {
    template: '#cpn',
    data() {
      return {
        title: 'abc'
      }
    }
  })
// 组件是不能直接访问Vue实例中的data数据
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      // title: '我是标题'
    }
  })
 
</script>

为什么data在组件中必须是一个函数呢?

  • 首先,如果不是一个函数,Vue直接就会报错。
  • 其次,原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
 <!--组件实例对象-->
  <div id="app">
    <cpn></cpn>
    <cpn></cpn>
    <cpn></cpn>
  </div>
 
  <template id="cpn">
    <div>
      <h2>当前计数: {{counter}}</h2>
      <button @click="increment">+</button>
      <button @click="decrement">-</button>
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>
    // 1.注册组件
    const obj = {
      counter: 0
    }
    Vue.component('cpn', {
      template: '#cpn',
      // data() {
      //   return {
      //     counter: 0
      //   }
      // },
      data() {
        // 会一起改变
        return obj
      },
      methods: {
        increment() {
          this.counter++
        },
        decrement() {
          this.counter--
        }
      }
    })
 
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊'
      }
    })
  </script>
  <script>
    const object = {
      name: 'why',
      age: 18
    }
 
 
    // function abc() {
    // 共用一个对象
    //   return object;
    // }
 
    function abc() {
      // 每调用一次函数都返回一个新的对象
      return {
        name: 'why',
        age: 18
      }
    }
 
    let obj1 = abc();
    let obj2 = abc();
    let obj3 = abc();
 
    obj1.name = 'kobe'
    console.log(obj2);
    console.log(obj3);
  </script>

 父子组件的通信(数据的传递)

  • 通过props向子组件传递数据(父传子
  • 通过事件向父组件发送消息(子传父

父级向子级传递---props

  props基本用法

<div id="app">
  <!--<cpn v-bind:cmovies="movies"></cpn>-->

  <!-- 没有v-bind直接这样写是给prop传递一个静态的值,也就是说movies不是一个变量而是一个字符串 -->
  <!--<cpn cmovies="movies" cmessage="message"></cpn>-->

  <!-- 步骤2 通过:cmessage="message" 将data中的数据传给子组件props -->
  <cpn :cmessage="message" :cmovies="movies"></cpn>
</div>


<!-- 子组件 -->
<template id="cpn">
  <div>
    <!-- 步骤3 将props中的值显示在子组件中 -->
    <ul>
      <li v-for="item in cmovies">{{item}}</li>
    </ul>
    <h2>{{cmessage}}</h2>
  </div>
</template>

<script src="../js/vue.js"></script>
<script>
  // 父传子: props

  // -------子组件------
  const cpn = {
    template: '#cpn',

    // 子组件通过prop接收  我们能够在组件实例中访问这个值,就像访问 data 中的值一样

    /* ***步骤1*** 在 子组件 定义props */
    // ****方式1:字符串数组,数组中的字符串就是传递时的名称(之后要引用的变量名)
    // props: ['cmovies', 'cmessage'], // 不要把元素当成字符串,把它当成数组




    data() {
      return {}
    }
  }


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

<!--
  步骤:
  1.在子组件里写props
  2.在子组件的标签加上v-bind  <cpn v-bind:props里定义的名称="父组件data数据名称"></cpn>
  3.将props中的值显示在子组件中
 -->

<!--
工厂函数
  1,它是一个函数。
  2,它用来创建对象。
  3 ,它像工厂一样,“生产”出来的函数都是“标准件”(拥有同样的属性)
-->

props数据验证---对象写法

// ***方式2:对象,对象可以设置传递时的类型,也可以设置默认值等->当需要对props进行类型等验证时
      props: {
        // 1.类型限制
        // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
        // cmovies: Array,
        // cmessage: String,
 
        // 多个可能的类型
        // propB: [String, Number],
 
        // 2.提供一些默认值, 以及必传值
        cmessage: {
          type: String,
          default: 'aaaaaaaa',
          required: true // 必填的字符串
        },
        // 类型是对象或者数组时, 默认值必须是一个工厂函数
        cmovies: {
          type: Array,
          default () {
            return {
              message: 'hello'
            }
          }
        },
        // 自定义验证函数
        propF: {
          validator: function (value) {
            // 这个值必须匹配下列字符串中的一个
            return ['success', 'warning', 'danger'].indexOf(value) !== -1
          }
        }
 
      },

props中的驼峰标识

 
  <div id="app">
    <!-- v-bind 不支持驼峰 需要换成 -  -->
    <cpn :c-info="info" :child-my-message="message" v-bind:class></cpn>
  </div>
 
  <template id="cpn">
    <div>
      <h2>{{cInfo}}</h2>
      <h2>{{childMyMessage}}</h2>
    </div>
  </template>
 
  <script src="../js/vue.js"></script>
  <script>
    const cpn = {
      template: '#cpn',
      props: {
        // 在这里使用驼峰 :c-info="info" 那里要用 -
        cInfo: {
          type: Object,
          default () {
            return {}
          }
        },
        childMyMessage: {
          type: String,
          default: ''
        }
      }
    }
 
    const app = new Vue({
      el: '#app',
      data: {
        info: {
          name: 'why',
          age: 18,
          height: 1.88
        },
        message: 'aaaaaa'
      },
      components: {
        cpn
      }
    })
  </script>

子级向父级传递---自定义事件

子级向父级传递

 
  <!--父组件模板-->
  <div id="app">
    <!-- 3.在父组件子标签中,通过v-on来监听子组件事件 并添加一个响应该事件的处理方法 -->
    <cpn @item-click="cpnClick"></cpn>
  </div>
 
  <!--子组件模板-->
  <template id="cpn">
    <div>
      <!-- 1.在子组件中创建一个按钮,给按钮绑定一个点击事件 -->
      <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) {
          // 发射事件: 自定义事件
          // 2.在子组件中,通过$emit()来触发事件
          this.$emit('item-click', item)
          // 注意!!!!这里的$emit事件名不要写成驼峰!!!脚手架里可以,会先编译成一个组件对象render函数
        }
      }
    }
 
    // 父组件 
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊'
      },
      components: {
        cpn
      },
      methods: {
        cpnClick(item) { // 这里的参数是接收子组件传过来的数据的
          console.log('cpnClick', item);
          
        }
      }
    })
  </script>

父传子--结合双向绑定案例

<!-- 父组件 -->
  <div id="app">
    <h3>父组件</h3>
    <h3>-----num1----</h3>
    <h3>{{num1}}</h3>
    <h3> -----num2----</h3>
 
    <h3>{{num2}}</h3>
    <hr>
    <cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change" />
  </div>
 
  <!-- 子组件 -->
  <template id="cpn">
    <div>
      <!-- 这样写会报错 应该是由父组件修改它,避免直接修改props的值 -->
      <!-- 
        <input v-model="number1" type="text" />
      <input v-model="number2" type="text" />
     -->
 
      <h3>子组件</h3>
 
      <h3> -----number1----</h3>
      <!-- 为什么props也会跟着一起变? -> number1绑定的是父组件num1 -->
      <h2>props:{{number1}}</h2>
      <h2>data:{{dnumber1}}</h2>
 
      <!--<input type="text" v-model="dnumber1">-->
      <!-- v-model的本质 用@input来传值 -->
      <input type="text" :value="dnumber1" @input="num1Input">
 
      <h3>-----number2----</h3>
 
      <h2>props:{{number2}}</h2>
      <h2>data:{{dnumber2}}</h2>
      <!--<input type="text" v-model="dnumber2">-->
      <input type="text" :value="dnumber2" @input="num2Input">
    </div>
  </template>
 
  <script src="../js/vue.js"></script>
  <script>
    // 子组件
    const cpn = {
      template: '#cpn',
      props: {
        number1: Number,
        number2: Number
      },
      data() {
        return {
          dnumber1: this.number1,
          dnumber2: this.number2
        }
      },
      methods: {
        num1Input(event) {
          // 1.将input中的value赋值到dnumber中
          this.dnumber1 = event.target.value;
 
          // 2.为了让父组件可以修改值, 发出一个事件
          this.$emit('num1change', this.dnumber1)
 
          // 3.同时修饰dnumber2的值
          this.dnumber2 = this.dnumber1 * 100;
          this.$emit('num2change', this.dnumber2);
        },
        num2Input(event) {
          this.dnumber2 = event.target.value;
          this.$emit('num2change', this.dnumber2)
 
          // 同时修饰dnumber1的值
          this.dnumber1 = this.dnumber2 / 100;
          this.$emit('num1change', this.dnumber1);
        }
      }
 
 
    }
 
 
    // 父组件
    const app = new Vue({
      el: '#app',
      data: {
        num1: 1,
        num2: 0
      },
      methods: {
        num1change(value) {
          // value传过来的是string类型,需要转换成数字
          this.num1 = parseFloat(value)
        },
        num2change(value) {
          this.num2 = parseFloat(value)
        }
      },
      components: {
        cpn
      }
    })
  </script>

父传子--结合双向绑定案例(watch实现)

 
<div id="app">
  <cpn :number1="num1"
       :number2="num2"
       @num1change="num1change"
       @num2change="num2change"/>
</div>
 
<template id="cpn">
  <div>
    <h2>props:{{number1}}</h2>
    <h2>data:{{dnumber1}}</h2>
    <input type="text" v-model="dnumber1">
    <h2>props:{{number2}}</h2>
    <h2>data:{{dnumber2}}</h2>
    <input type="text" v-model="dnumber2">
  </div>
</template>
 
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      num1: 1,
      num2: 0
    },
    methods: {
      num1change(value) {
        this.num1 = parseFloat(value)
      },
      num2change(value) {
        this.num2 = parseFloat(value)
      }
    },
    components: {
      cpn: {
        template: '#cpn',
        props: {
          number1: Number,
          number2: Number,
          name: ''
        },
        data() {
          return {
            dnumber1: this.number1,
            dnumber2: this.number2
          }
        },
        watch: {
          dnumber1(newValue) {
            this.dnumber2 = newValue * 100;
            this.$emit('num1change', newValue);
          },
          dnumber2(newValue) {
            this.number1 = newValue / 100;
            this.$emit('num2change', newValue);
          }
        }
      }
    }
  })
</script>

补充:监听器watch

  • watch选项能够监听值的变化。
 <!-- watch选项能够监听值的变化 -->
    <div id="app">
        <input type="text" v-model="number">
    </div>
    <script src='../js/vue.js'></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                number: 1,
            },
            watch: {
                // 监听number变量,当它有变化执行
                /* number(newValue, oldValue) { // newValue新值,oldValue旧值 参数只写newValue也可以
                    console.log('newVal', newValue);
                    console.log('oldVal', oldValue);
                } */
                // 也可以这样写
                number: {
                    handler(newValue, oldValue) { //handler方法就是你watch中需要具体执行的方法
                        console.log('newVal', newValue);
                        console.log('oldVal', oldValue);
                    },
                    immediate: true
                    //immediate为true时则立即触发回调函数;如果为false,则和上面的例子一样,不会立即执行回调。
                }
            }
        })
    </script>

父子组件的访问

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

  • 组件访问子组件:使用$children或$refs
  • 组件访问组件:使用$parent

父子组件的访问方式: $refs(父访问子)

 <div id="app">
    <cpn></cpn>
    <cpn></cpn>
 
    <my-cpn></my-cpn>
    <y-cpn></y-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);
          this.$children[0].showMessage(); // 子组件的方法可以听过这种方式调用
          // this.$children是一个数组类型,它包含所有子组件对象。
 
          // for (let c of this.$children) {
          //   console.log(c.name);
          //   c.showMessage();
          // }
          // console.log(this.$children[3].name);
 
          // 明确获取其中一个特定的组件,这个时候就可以使用$refs
 
          // 2.$refs reference(引用)  => 对象类型, 默认是一个空的对象 ref='bbb'
          console.log(this.$refs.aaa.name);
        }
      },
      components: {
        cpn: {
          template: '#cpn',
          data() {
            return {
              name: '我是子组件的name'
            }
          },
          methods: {
            showMessage() {
              console.log('showMessage');
            }
          }
        },
      }
    })
  </script>

父子组件的访问方式: $parent(子访问父)、$root(根组件) 

 
<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.访问父组件$parent
                // console.log(this.$parent);
                // console.log(this.$parent.name);
 
                // 2.访问根组件$root
                console.log(this.$root);
                console.log(this.$root.message);
              }
            }
          }
        }
      }
    }
  })
</script>

插槽slot

slot的基本使用

 
 
  <!--
    插槽
      插槽,也就是slot,是组件的一块HTML模板,这块模板 显示不显示、以及 怎样显示 由父组件来决定
    
    单个插槽 | 默认插槽 | 匿名插槽
      可以放置在组件的任意位置 一个组件中只能有一个该类插槽
      
      1.插槽的基本使用 <slot></slot>
    
      2.插槽的默认值 <slot>button</slot>
    
      3.如果有多个值, 同时放入到组件进行替换时, 一起作为替换元素
-->
 
  <div id="app">
    <cpn></cpn>
 
    <cpn>
      <span>哈哈哈</span>
    </cpn>
 
    <cpn>
      <i>呵呵呵</i>
    </cpn>
 
    <cpn>
      <i>呵呵呵</i>
      <div>我是div元素</div>
      <p>我是p元素</p>
    </cpn>
 
    <cpn></cpn>
    <cpn></cpn>
 
    <!-- 如果不使用插槽,往组件标签里写东西是没有效果的 -->
    <cpn2>略略略</cpn2>
  </div>
 
 
  <template id="cpn">
    <div>
      <h2>我是组件</h2>
      <p>我是组件, 哈哈哈</p>
      <slot><button>按钮</button></slot>
      <!--<button>按钮</button>-->
    </div>
  </template>
  <template id="cpn2">
    <div>
      <h2>我是组件222</h2>
      <p>我是组件22222, 哈哈哈</p>
    </div>
  </template>
 
  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊'
      },
      components: {
        cpn: {
          template: '#cpn'
        },
        cpn2: {
          template: '#cpn2'
        }
 
      }
    })
  </script>
 

具名插槽slot

使用方式:只要给slot元素一个name属性即可 <slot name='myslot'></slot>

vue2.5写法:

<!-- 
  具名插槽其实就是给插槽取个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,
  而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中。
  具名插槽就可以有很多个,只要名字(name属性)不同就可以了
 -->
  <div id="app">
 
    <!-- 这个只能替换没有名字的插槽-->
    <cpn><span>没有名字的替换</span></cpn>
    <!-- vue2.5的写法  -->
    <!-- 下面这两个还是会显示没有名字的插槽的默认内容 -->
    <cpn><span slot="center">标题</span></cpn>
    <cpn><button slot="left">返回</button></cpn>
  </div>
 
 
  <template id="cpn">
    <div>
      <!-- 没有名字的插槽 -->
      <slot>没有名字的插槽默认内容</slot>
 
 
      <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>

vue2.6写法:

   <!-- 
  注意 v-slot 只能添加在 < template > 上,只有当被提供的内容只有默认插槽时,
  组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot 直接用在组件
 -->
    <div id="app">
        <!-- 默认 -->
        <cpn></cpn>
        <hr>
        <!-- 使用v-slot替换 -->
        <cpn>
            <!-- vscode 快捷语法 vslot-named -->
            <template v-slot:left>
                <span>返回</span>
            </template>
        </cpn>
        <cpn>
            <!--任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。或者可以给他起名default-->
            <!--<template v-slot:default>
                    我是内容
                </template>-->
 
            <template v-slot:center>
                <span>标题</span>
            </template>
            <span>替换没有名字的插槽</span>
        </cpn>
        <cpn>
        <!-- 
        跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。
        例如 v-slot:header 可以被重写为 #header:,前提是必须要有插槽名!!!
        -->
            <template #right>
                <span>替换后的右边</span>
            </template>
        </cpn>
    </div>
    <template id="cpn">
        <div>
            <slot name="left"><span>左边</span></slot>
            <slot name="center"><span>中间</span></slot>
            <slot name="right"><span>右边</span></slot>
            <slot>默认插槽内容</slot>
        </div>
    </template>
    <!-- 需要重新引入一个vue2.6之后的版本 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
    <script>
        const cpn = {
            template: '#cpn'
        }
        const app = new Vue({
            el: '#app',
            data: {},
            components: {
                cpn
            }
        })
    </script>

编译作用域

 <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="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊',
        isShow: true
      },
      components: {
        cpn: {
          template: '#cpn',
          data() {
            return {
              isShow: false
            }
          }
        },
      }
    })
  </script>

作用域插槽的使用

vue2.6之前写法:

<!-- vue2.6之前写法 -->
  <div id="app">
    <!-- 以下三个组件 内容一样,样式不同 -->
    <cpn></cpn>
 
    <cpn>
      <!--slot-scope声明属性名 接收子组件传递的数据pLanguages-->
      <template slot-scope="slot">
        <!-- 在dom标签使用该数据,通常用插值表达式接收具体数据 -->
        <!--<span v-for="item in slot.data"> - {{item}}</span>-->
        <h3>{{slot}}</h3>
        <span>{{slot.data.join(' - ')}}</span>
      </template>
    </cpn>
 
 
    <cpn>
      <template slot-scope="slot">
        <!--<span v-for="item in slot.data">{{item}} * </span>-->
        <span>{{slot.data.join(' * ')}}</span>
      </template>
    </cpn>
 
    <!--<cpn></cpn>-->
  </div>
 
  <!-- 子组件 template -->
  <template id="cpn">
    <div>
      <!-- 作用域插槽要求,在slot上面绑定数据 -->
      <slot :data="pLanguages">
        <ul>
          <li v-for="item in pLanguages">{{item}}</li>
        </ul>
      </slot>
      <hr>
    </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>

vue2.6之后写法:

 
    <div id="app">
        <!-- 默认 -->
        <h4>默认</h4>
        <cpn></cpn>
        <hr>
        <h4>替换样式</h4>
        <cpn>
            <!-- 具名插槽和作用域插槽混用 -->
            <template v-slot:slot1='props1'>
                <!-- 
                <span>
                    {{props1}}
                </span> -->
 
                <span>{{props1.data1.join('-')}}</span>
                <h3>
                    {{props1.msg}}
                </h3>
            </template>
            <template v-slot:slot2="props2">
                <h2 style="color: red;">
                    {{props2.data2}}
                </h2>
            </template>
        </cpn>
        <!--
            当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。
            这样我们就可以把 v-slot 直接用在组件上,但是不能和具名插槽混用
            -->
        <cpn v-slot="props3">
            <template>
                <h3 style="color: blue;">
                    {{props3.data3}}
                </h3>
            </template>
        </cpn>
    </div>
    <template id="cpn">
        <div>
            <!-- 可以传多个值 所有的值会包含在一个对象中 在父组件中v-slot=""中定义名字接收 -->
            <slot :data1='movies' :msg='message' name='slot1'>
                <ul>
                    <li v-for="(item, index) in movies" :key="index">
                        {{item}}
                    </li>
                </ul>
            </slot>
            <slot :data2='name' name='slot2'>
                {{name}}
            </slot>
            <slot :data3='defult'>默认插槽</slot>
        </div>
    </template>
    <!-- 需要重新引入一个vue2.6之后的版本 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
    <script>
        const cpn = {
            template: '#cpn',
            data() {
                return {
                    movies: ['战狼', '鬼吹灯', '盗墓笔记'],
                    message: '你好呀',
                    name: 'yangyanyan',
                    defult: '我是默认的数据'
                }
            },
        }
        const app = new Vue({
            el: '#app',
            data: {},
            components: {
                cpn
            }
        })
    </script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值