VUE组件---day04

发布于:2022-12-09 ⋅ 阅读:(605) ⋅ 点赞:(0)

今日总结

一、vue组件

1、全局组件定义的四种方式

2、使用components属性定义局部子组件(私有组件)

3、组件中展示数据和响应事件

4、使用 :is  属性来切换不同的子组件,并添加切换动画

5、组件传值:父传子

二、slot插槽

1、插槽的使用

2、插槽的使用-具名插槽

3、插槽的使用-默认插槽

其他

今日总结

一、vue组件

什么是组件:组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可。

组块化和模块化的不同

模块化:是从代码的逻辑角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一(实现   高内聚低耦合      模块之间低耦合    模块内部高内聚)

组块化:是从UI界面的角度进行划分;前端的组件化,方便UI组件的重用

1、全局组件定义的四种方式

        1、使用 Vue.extend 配合 Vue.component 方法:

        2、直接使用 Vue.component 方法:

        3、将模板字符串定义到 script 标签中,同时需要使用 Vue.component 来定义组件

        4、将模板字符串定义到 template 标签中,同时需要使用 Vue.component 来定义组件

        注意:组件中的 DOM 结构,有且只能有唯一的根元素来进行包裹

                  组件名不能和 h5 标签重复 不使用内置或保留的HTML元素作为组件id

                  标签名不区分大小写 注意不能使用驼峰命名法

示例:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>全局定义组件定义的四种方式</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
  <div id='app'>
    <!-- 1 -->
    <login></login>
    <!-- 2 -->
    <register></register>

    <!-- 3 -->
    <tmpl></tmpl>

    <!-- 4 -->
    <account></account>
  </div>

  <!-- 3 -->
  <script id="tmpl" type="x-template">
    <div><a href="#">登录</a> | <a href="#">注册</a></div>
  </script>

  <!-- 4 -->
  <template id="account">
    <div>
      <p>我是一个p标签</p>
    </div>
    <!-- 注意:组件中的DOM结构,有且只能有唯一的根元素 -->
    <!-- <div>      
      <strong>我是一个Vue组件</strong>
    </div> -->
  </template>




  <script>
  
  // 组件名不能和 h5 标签重复 不使用内置或保留的HTML元素作为组件id
  // 标签名不区分大小写 注意不能使用驼峰命名法

  // 1、使用 Vue.extend 配合 Vue.component 方法
  var login = Vue.extend({  // 全局声明
    template:'<h1>登录</h1>'
  })
  Vue.component('login',login)   // 全局注册 (名字 模板)
  
  // 2、直接使用 Vue.component 方法
  Vue.component('register',{
    template:'<h2>注册</h2>'
  })

  // 3、将模板字符串,定义到 script 标签中
  // 同时,需要使用 Vue.component 来定义组件
  Vue.component('tmpl',{
    template:'#tmpl'
  })

  // 4、以上三种方法现在不怎么用了,通常使用下面的使用方法
  // 将模板字符串定义到template标签中
  Vue.component('account',{
    template:'#account'
  })


  let vm = new Vue({
    el: '#app',
    data: {
    },
    methods: {
    },
  })
  </script>
</body>
</html>

2、使用components属性定义局部子组件(私有组件)

components与methods、data同级

let vm = new Vue({

    el: '#app',

    data: {

    },

    methods: {

    },

    // 私有定义方式

    components:{

      'myheader':{   // 名字

        template:'#myheader'    // 模板

      }

    }

  })

示例:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>私有组件</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
  <div id='app'>
   

    <!-- 4 -->
    <myheader></myheader>
  </div>

  

  <!-- 4 -->
  <template id="myheader">
    <div>
      <p>我是一个p标签</p>
      <p>我是一个p标签</p>
      <p>我是一个p标签</p>
    </div>
    <!-- 注意:组件中的DOM结构,有且只能有唯一的根元素 -->
    <!-- <div>      
      <strong>我是一个Vue组件</strong>
    </div> -->
  </template>

  <script>
  
  // 标签名不区分大小写 注意不能使用驼峰命名法

 
  // 4、
  // 将模板字符串定义到template标签中
  // Vue.component('account',{
  //   template:'#account'
  // })


  let vm = new Vue({
    el: '#app',
    data: {
    },
    methods: {
    },
    // 私有定义方式
    components:{
      'myheader':{   // 名字
        template:'#myheader'    // 模板
      }
    }
  })
  </script>
</body>
</html>

3、组件中展示数据和响应事件

在组件中,data需要被定义为一个方法

为什么?

因为要实现数据隔离

示例:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title></title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
  <div id='app'>
    <button @click="flag = !flag"> 点我 </button>
    <!-- 子组件的应用 -->
    <component is="mine"></component>
    <component :is="flag?'login':'mine'"></component>
  </div>

  

  <!-- 4 -->
  <template id="login">
    <div>
      登录
    </div>
   
  </template>
  <template id="mine">
    <div>
      用户名
    </div>
   
  </template>




  <script>
    Vue.component('mine',{
      template:'#mine',
    })
  // 全局定义组件
  Vue.component('login',{
    template:'#login',
    // 为什么组件中的data属性必须定义为一个方法并返回一个对象
    // 要 数据隔离
    data(){
      return {
        msg:'hello',
        num:6
      }
    },
    methods:{
      addn(n){
        this.num += n
      }
    },
    beforeCreate(){
      console.log('beforeCreate');
    },
    created(){
      console.log('created');
    },
    beforeDestroy(){
      console.log('beforeDestroy');
    },
    destroyed(){
      console.log('destroyed');
    },
  })


  let vm = new Vue({
    el: '#app',
    data: {
      flag:true,
    },
    methods: {
    },
  })
  </script>
</body>
</html>

4、使用 :is  属性来切换不同的子组件,并添加切换动画

使用 component 标签,来引用组件,并通过 :is 属性来确定要加载的组件

示例:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title></title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <style>
    .v-leave-to,
    .v-enter{
      opacity: 0;
      transform: translateX(200px);
    } 
    .v-enter-to,
    .v-leave{
      opacity: 1;
      transform: translateX(0px);
    }
    .v-enter-active,
    .v-leave-active{
      transition: all 2s;
    }
    div{
      width: 100px;
    }
  </style>
</head>
<body>
  <div id='app'>
    <button @click="flag = !flag"> 点我 </button>
    <!-- 子组件的应用 -->
    <component is="mine"></component>
    <!-- <component :is="flag?'login':'mine'"></component> -->

    组件动画 1
    <transition mode="out-in">
      <component :is="flag?'login':'mine'"></component>
    </transition>
    <br>
    <br>
    <br>
    <br>
    组件动画 2
    <transition mode="out-in">
      <!-- <component :is="flag?'login':'mine'"></component> -->
      <login v-if="flag"></login>
      <mine v-else></mine>
    </transition>


  </div>

  

  <!-- 4 -->
  <template id="login">
    <div>
      登录
    </div>
   
  </template>
  <template id="mine">
    <div>
      用户名
    </div>
   
  </template>




  <script>
    Vue.component('mine',{
      template:'#mine',
    })
  // 全局定义组件
  Vue.component('login',{
    template:'#login',
    // 为什么组件中的data属性必须定义为一个方法并返回一个对象
    // 要 数据隔离
    data(){
      return {
        msg:'hello',
        num:6
      }
    },
    methods:{
      addn(n){
        this.num += n
      }
    },
    beforeCreate(){
      console.log('beforeCreate');
    },
    created(){
      console.log('created');
    },
    beforeDestroy(){
      console.log('beforeDestroy');
    },
    destroyed(){
      console.log('destroyed');
    },
  })


  let vm = new Vue({
    el: '#app',
    data: {
      flag:true,
    },
    methods: {
    },
  })
  </script>
</body>
</html>

5、组件传值:父传子

<body>

  <div id='app'>

    <!-- 1、接受来自父亲的变量和函数,注意不要和子组件data中的变量重名 -->

    <test :weather="weather" :func="log_father" text="今天是个什么天气">天气

      <template v-slot:yang>

        <!-- <p v-text="msg"></p> -->   <!-- 报错原因:此处写的 msg 是父的变量,不是子的变量 -->

      </template>

    </test>

  </div>

  <template id="test">

    <!-- 3、在子组件中进行使用 -->

    <!-- 传过来之后,使用方法就和在子组件中data和methods相同,但是不能修改,要修改的话要在父亲中修改 -->

    <div>

      <slot></slot>

      <h1>我是子组件</h1>

      <button @click="log1"> 点我 </button>  <!-- 在子组件中写的事件和变量,是来自子组件的事件变量 -->

      <!-- 插槽 -->

      <slot name="yang"></slot>

      <!-- weather为父亲传过来的值 -->

      <p v-text="weather"></p>     <!-- 变量父传子之后,在子组件中就可以使用父组件的变量和函数了 -->

      <!-- func为父亲传过来的函数 -->

      <button @click="func">来自父亲的事件</button>

    </div>

  </template>

  <!--

    总结一下:真的很像继承

      在进行组件间父传子(变量和函数)时,1,2,3 + 注意

   -->

  <script>

  const vm = new Vue({

    el: '#app',

    data: {

      weather:'sun'

    },

    methods: {

      log_father(){

        console.log('我是父亲');

      }

    },

    components:{  // 定义私有子组件

      test:{  // 子组件的名字

        template:'#test',   // 子组建的模板

        data(){

          return {

            type:'good',

            msg:'',

          }

        },

        // 2、接受变量和函数,确定接收到变量和方法的数据类型

        props:{

          weather:String,

          text:String,

          func:Function,

        },

        // 传过来之后,使用方法就和在子组件中data和methods相同,但是不能修改,要修改的话要在父亲中修改

        methods:{

          log1(){

            console.log(this.text);

            console.log(this.weather);

            this.msg = this.weather

            console.log(this.type);

          }

        },

      }

    }

  })

  </script>

</body>

二、slot插槽

1、插槽的使用

在子组件中放一个占位符 <slot></slot>

在父组件中给这个占位符填充内容

如果子组件不使用插槽的话,父组件如果需要往子组件中填充模板后者html是没有办法做到的

2、插槽的使用-具名插槽

具名插槽就是给插槽取个名字,一个子组件可以放多个插槽,而且可以放在不同的地方,二负组件填充内容是,可以根据这个名字把内容填充到对应的插槽中

父组件填充内容,父组件通过 v-slot:name 的方式指定到对应的插槽中

子组件在写插槽时,加上name属性

3、插槽的使用-默认插槽

默认插槽就是指没有名字的插槽,子组件未定义的名字的插槽,父级将会把 未指定插槽的填充的内容填充到默认插槽中。

示例:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>插槽</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
  <style>
    ul{
      display: flex;
      justify-content: space-between;
      flex-wrap: wrap;
      list-style: none;
    }
    li{
      width: 19%;
    }
    li img{
      width: 100%;
      height: 120px;
    }
    h2{
      text-align: center;
    }
  </style>
</head>
<body>
  <div id='app'>

    <!-- 免费课程 -->
    <course :type="type" page-size="10">
      免费  <!--默认插槽-->
      <template v-slot:fee>免费</template>
    </course>

    <!-- 精品课程 -->
    <course type="boutique">
      精品
      <template v-slot:fee>
        <p>
          我是精品课程
        </p>
      </template>
    </course>

    <!-- 折扣课程 -->
    <course type="discount">
      限时折扣
      <template v-slot:fee>
        <p>
          我是折扣课程
          <!-- {{item.coursePrice}} -->
        </p>
      </template>
    </course>
  </div>


  <template id="course">
    <div>
      <h2><slot><!--默认插槽--></slot>课程</h2>
      <ul>
        <li v-for="item in freeCourseList" :key="item.id">
          <img :src="item.bannerFileUrl" alt="">
          <div>{{item.courseTitle}}</div>
          <div>共 {{item.learningNum}} 节课 | {{item.participationsCount}} 人报名</div>
          <div><slot name="fee"></slot></div>
        </li>
      </ul>
    </div>
  </template>




  <script>


  Vue.component('course',{
    template:'#course',
    data(){
      return {
        freeCourseList:[]
      }
    },
    // 接受传值
    props:{
      // 自己定义接受
      type:String,
      size:Number,
      // pageSize:Number,
      // 定义多个数据类型
      // pageSize:[Number,String],
      pageSize:{
        type:[Number,String],
        // default:5,
        // 注意默认参数使用引用类型时,default要写成函数返回值的形式:用于数据隔离
        default(){
          return 5
        }
      }
    },
    methods:{
      getCourseList(type='free',pageNum=1,pageSize=5){
        let formurl = new URLSearchParams();
          formurl.append("type", type);
          formurl.append("pageNum", pageSize);
          formurl.append("pageSize", pageNum);
          return axios.post("http://1.117.81.216:8086/weChat/applet/course/list/type", formurl);
      }
    },
    created(){
      console.log(this);
      console.log(this.pageSize);  // 数据的父传子 可读不可改
      this.getCourseList(this.type,this.pageSize,1).then(res=>{
        this.freeCourseList = res.data.rows
      })
    }
  })


  const vm = new Vue({
    el: '#app',
    data: {
      type:'free'
    },
    methods: {
    },
  })
  </script>
</body>
</html>

其他

1、vue动画通过 v-if v-show 来pending动画的内容,以此来控制动画的产生

2、一个好用的第三方动画库 animate.css 需要引入文件,之后直接在<transition>标签中使用类名即可

3、<transition>标签中的 mode 属性只能识别组件,不能直接识别标签

<transition mode="out-in">

      <component :is="flag?'login':'mine'"></component>

</transition>

单词

1component 组件

2template 模板

3props 接受传值

本文含有隐藏内容,请 开通VIP 后查看