Vue-组件相关的知识点

Vue组件相关的知识点

学习内容:

Vue组件相关的知识点

1、 全局组件
2、 局部组件
3、 组件间相互传参
4、 组件相互访问
5、插槽


说点啥:

嗯~~又是充实的一天,今天学习了组件相关的知识点,记录下来,方便以后自己查阅,努力,加油,欧里给

学习产出:

组件分类: 页面级组件、业务上可重复的基础组件、与业务无关的独立组件

全局组件的创建

简洁

app.component("box1",{
  template:`
    <div style="width:350px;height:200px;background-color:#f00">
      <Mybox></Mybox>
      </div>
  `
})

具体示例

<script>
const app = Vue.createApp({
	data(){return{msg:1}}
  }
})
// 注册全局组件
// 全局组件可在当前实例中任意位置使用
app.component("Mybox",{
  template:`
    <div style="width:150px;height:100px;background-color:#faf"></div>
  `
})
// 另一个全局组件
// 如果两个全局组件想要相互只用,需要在对应的组件的模板中调用
app.component("box1",{
  template:`
    <div style="width:350px;height:200px;background-color:#f00">
      <Mybox></Mybox>
      </div>
  `
})
app.mount('#app')

局部组件

vue的局部组件只能用在注册其的页面上
    eg:有两个子组件被vue实例引用了,这个vue实例可以用这两个子组件,但是这两个子组件不能相互使用,如果a子组件想用b子组件,那么需要在a中注册一下

let b={
  template:`
    <div style="width:350px;height:200px;background-color:#f00">
      <a></a>
      </div>
  `,
  components:{
    a
  }
}

组件间传参

注意:组件传参的属性名不能使用驼峰式,因为浏览器都会将其解析成小写

父→子

父组件中:
    在调用子组件的时候 通过动态绑定属性的方式,将数据传过去,属性名和数据名最好一样

 <div id="app">
    <h1>父传子</h1>
    <box :colleges="msg2" :branch="branch"></box>
  </div>

子组件中:
在子组件中通过prop来接收父组件传过来的数据,prop里是父组件传过来的属性名,要加引号

<script>
 const Box = {
      template: "#box",
      // 接收父祖件的数据
      props: ["colleges", "branch"]
    }
</script>

prop的类型

  • 1.只指定名称
    props: [“colleges”, “branch”]
  • 2.指定名称和类型
    注意此时的prop已经是对象了
    props:{
    colleges:String,
    branch:Number
    }
  • 3.指定名称/类型/必要性/默认值
    props:{
    colleges:{type:String,required:true,default:xxx},
    branch:{type:Number,required:true,default:xxx},
    }
    prop中数据的类型有
    String/Number/Boolean/Array/Object/Date/Function/Symbol/自定义类型

子→父

    使用场景,子组件更改某个操作希望通知父组件,让父组件做出操作、或子组件像父组件传递数据

子组件中:
创建子组件,当子组件里的按钮被点了触发btnClick事件,然后通过$emit会发射一个事件

<script>
    const box = {
      template: "#box",
      methods:{
        btnClick(){
          alert("你是🐕🐕*10")
          // 发射自定义事件
          // 这里发射事件的名称不能是驼峰命名
          // 两个参数,第一个是事件名称,第二个是数据
          // 多个数据的传递一般采用对象或者数组的方式
          // this.$emit("send-click","我是恁爹的数据","1","2")
          // 可以发射多个不同的自定义事件
          this.$emit("send-click",{name:"张三",age:13})
        }
      }
    }
</script>

父组件中:
    父组件绑定子组件发射的自定义事件,当子组件一发射这个事件,那么就会执行绑定的函数

<div id="app">
    <box @send-click="clickFun"></box>
</div>
<script>
//methods中
  methods:{
        // 接收父组件自定义事件是没有事件对象的
        // 子组件自定义函数中的形参不是事件对象,而是子组件传来的值
        clickFun(val){
           console.log("子组件的事件被点击了");
           console.log(val);
        },
      }
 </script>

组件间的访问

父组件访问子组件

在调用子组件的时候需要为其设置一个ref名称,代表该子组件

父组件:

<div id="app">
  <!-- 这里需要给子组件绑定一个ref,代表当前组件的名称 -->
  <lk-box ref="box1"></lk-box>
  <lk-box ref="box2"></lk-box>
  <lk-box ref="box3"></lk-box>
  <button @click="getChildrenComponent">click me </button>
</div>

在调用该子组件的父组件中通过this.$refs.ref名访问

父组件:

<script>
methods:{
    getChildrenComponent(){
      // $refs每个实例都会有
      // this.$refs.box1表示拿到box1组件了,然后可以其经行操作
     console.log(this.$refs.box1.msg);
    //  this.$refs.box1.btnClick()
     this.$refs.box2.msg="我偷偷的更改了信息呢"
    }
  }
</script>

子组件访问父组件

(不建议使用,破坏了子组件的封闭性)

设有两两个组件a和b,组件a引用了组件b,
此时组件a就是组件b的父组件,如果组件b
想要访问组件a,直接this.\$parent
(表示父组件a)即可,对其内容 . 操作即可。

访问根组件:this.$root

<script>
  const Btn = {
      template: `
      <button @click="plus">点击了{{count}}</button>
    `,
      data() {
        return {
          count: 0,
        }
      },
      methods: {
        plus() {
          this.count++;
          // this.$parent代表引用当前子组件的父组件
          console.log(this.$parent.a);//哈哈哈
          // console.log(this.$parent.$parent.msg);//郑工学院
          // this.$root表示访问根组件
          console.log(this.$root.msg);
        }
      }
    }
 </script>

插槽

插槽 v-slot(匿名插槽和具名插槽)

插槽是组件里面的一个知识点,所谓插槽就是在子组件中预留一个位置,
然后父组件在调用子组件的时候,可以在这块位置经行操作。
(比如说,一个页头好多地方用但是里面的细节不同需要单独设置,
但是整个结构是不变的)

匿名插槽

子组件:
    在子组件中用占位,slot标签中可以写东西,当父组件没有插入东西时,就使用默认的

 <template id="box">
    <div style="width: 200px;height:150px;background-color: #f00;">
      <p>淘!淘你喜欢!</p>
      <!-- <button>淘一下</button> -->
      <!-- 预留插槽 -->
      <slot>插槽的默认内容</slot>
    </div>
  </template>
  <script>
    const hhBox={
      template:"#box",
    }
  </script>

父组件:
    父组件在调用子组件的时候,在标签内部写东西,就会替换掉子组件的slot标签

<div id="app" >
  <hhbox>
    <button>淘一下</button>
  </hhbox>
  <hhbox>
    <input type="text" placeholder="请输入内容">
  </hhbox>
  <hhbox>
</div>

具名插槽

子组件:
    将每个插槽命名

 <template id="box">
    <!-- 头部 -->
    <header>
      <slot name="header">头部插槽</slot>
    </header>
    <!-- 主体 -->
    <!-- 此插槽是匿名插槽 -->
    <main>
      <slot >主体插槽</slot>
    </main>
    <!-- 脚部 -->
    <footer>
      <slot name="footer">脚部插槽</slot>
    </footer>
    <p>======================================</p>
  </template>
  <script>
    const MyBox = {
      template: "#box",
    }
  </script>

父组件:
  使用v-slot:插槽名即可将对应的内容替换到插槽中,template标签会被内容替换掉不占用位置
匿名插槽和具名插槽的相互使用:
    在子组件中,有匿名插槽也有具名插槽,在父组件中,具名插槽用v-slot:插槽名占用,用v-slot:default的模板会自动替换到匿名插槽中

<div id="app">
    <mybox>
      <template v-slot:header>
        <button>我是头部</button>
      </template>
      <!-- 使用v-slot:default可以将此模板替换为子组件的匿名插槽 -->
      <template v-slot:default>
        <input type="text" placeholder="我是主体">
      </template>
      <template v-slot:footer>
        <img src="1.jpg">
      </template>
    </mybox>
  </div>

渲染作用域

结论:父级模板里的所有内容都是在父级作用域中编译的
子级模板的所有内容都是在子级作用域中编译的

<div id="app">
 <!-- div会显示,说明用的数据是父组件里面的 -->
   //box是子组件 子组件和父组件中都有isShow,但是会调用父组件中的数据
 <box v-show="isShow"></box>
</div>

作用域插槽:

    子组件在预留插槽的时候,通过绑定属性的方式将子组的数据暂存到当前插槽中,父组件在使用插槽的时候通过变量接住数据,即可实现父组件中可以调用子组件的数据(直接在视图层经行操作),$refs必须实在js中经行操作
简而言之:数据是子组件的,由父组件传结构过来
子组件
通过绑定的属性的方式将数据绑定到插槽中

<template id="box">
	<!-- data:属性名,即父组件接收数据对象的键名,nameArr是值,可自定义 -->
  <slot :data="nameArr"></slot>
</template>
<script>
 const box = {
   template:"#box",
   data(){
     return{
       nameArr:["张三","李四","王五","赵六"]
     }
   }
 }
 </script>

父组件
    在调用子组件的时候,通过具名或者匿名插槽的方式,在其后面给个变量接住传过来的值,变量名可自定义,这个变量是一个对象,接住了子组件传来的数据

<box>
	//v-slot:default表示调用匿名插槽,也可以用具名插槽
    <template v-slot:default="slotProps">
      <!-- slotProps代表子组件插槽传来的数据对象 -->
      <!-- { "data": [ "张三", "李四", "王五", "赵六" ] } -->
      <div> {{slotProps}}</div>
    </template>
  </box>

动态组件

    当组件之间,切换的时候,有时候会想保持这些组件的状态,以避免反复重复渲染导致的性能问题
    根据数据的变化,结合component标签,来动态切换组件的显示
is属性动态绑定组件,

eg:按钮组件和输入框组件只能显示其一
首先创建两个全局组件

<script>
 app.component("c-button", {
      template: `
    <button>百度一下</button>
  `,
    });
    app.component("c-input", {
      template: `
  <input type="text" placeholder="请输入内容"/>
  `,
    })
</script>

然后在调用该组件的时候
    通过component标签和is属性,is后面的变量名称与哪个组件名相同,就会显示哪个组件
keep-alive标签:失活组件可以缓存
失活:比如切换输入框显示/隐藏的时候切换前输入的内容会没有,用来这个标签就不会出现这种情况

<div id="app">
    <keep-alive>
      <component :is="cItem"></component>
    </keep-alive>
    <p>-----------</p>
    <button @click="isShow">切换</button>
  </div>
//vue实例中
<script>
 data() {
        return {
          cItem: "c-button",
        }
      }
</script>

异步组件

    在大型应用中,我们可能将应用分割成一些小块的代码,并且只在需要的时候才从服务器加载一个模块
Vue中通过Vue.defineAsyncComponent来创建里面必须用Promise语法

<script>
   app.component("async-item", Vue.defineAsyncComponent(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve({
            template: `
                <div style="background-color:#faf;">这是一个从服务器端异步拿过来的全局组件的数据</div>
              `,
          })
        }, 2000)
      })
    }
    ))
</script>

生命周期函数

这里没写完,具体的可以去官方手册查看
在这里插入图片描述
在这里插入图片描述

侦听器watch

注意:要监听的数据和函数要同名
每个监听函数都有两个参数,一个代表当前的值,一个代表之前的值

<script>
const app = Vue.createApp({
  data(){
    return{
        price:5,    
    }
  },
  watch:{
    // 监听属性有两个参数 current:现在的值 prev之前的值
    price(current,prev){
      console.log(current,prev);
    }
  },
</script>

-计算属性和监听器的区别:

  1. 计算属性底层是靠watch实现的
  2. 计算属性在调用时需要在模板中渲染
  3. 计算属性默认深度依赖,watch默认浅度依赖
  4. 计算属性适合做筛选,不可异步,watch适合执行异步或开销较大的操作

单项数据流

vue中组件传参是单向数据
  单项数据流:在Vue中都是组件化开发,比如父组件的数据要给子组件用,也要给孙组件以及更深层次的子组件,这时要保证子组件不能修改数据,否则其他的数据都会变,这就是数据单向流

组件传参的快捷语法

注意:传参的时候以对象的方式,对象的键名要与接收参数的组件的props里面的名称相对应,然后在要调用的子组件标签以v-bind的方式传入

 <div id="app">
    <p>键名必须和子组件中props中的名称对应</p>
    <box v-bind="numObj"></box>
    <!-- 使用简洁语法底层解析是这样的 -->
    <!-- <box :num1="numObj.num1" :num2="numObj.num2" :num3="numObj.num3"></box> -->
  </div>
  <script>
    const box = {
    props:["num1","num2","num3"],
      template: `
      <div>数据1:{{num1}}</div>
      <div>数据2:{{num2}}</div>
      <div>数据3:{{num3}}</div>
    `,
    }
    const app = Vue.createApp({
      data() {
        return {
          numObj:{
            num1:100,
            num2:200,
            num3:300
          }
        }
      },
      components: {
        box
      }
</script>

no-props

  正统的数据传递,父组件在调用子组件的时候,通过属性绑定的方式将数据传递给子组件,子组件通过props接收即可,但是当想要传递一个样式或者class类的时候,用no-props传递比较简单,就是子组件内不用props接收
父组件:

<div id="app">
  <box msg="我是" style="background-color:red"></box>
</div>

全局子组件中:

  1. 父组件传值过来,子组件不用props接收,那么就会子组件的模板的元素中添加对应的属性
  2. 一般用no-props给子组件传递样式或class,如果子组件没有props接收数据,这时就会多出来样式属性

  结果:<div msg=“我是” style=“background-color:red”>我是全局子组件</div>

  1. 默认如果子组件内部只有一层包裹就会作用到爹身上,如果有多个平级元素no-props不生效
  2. 如果子组件的模板中有多个同一级别的标签,在每个标签上v-bind="$attrs",使得当前标签no-props生效
  3. 如果父组件传来多个属性,只需要个别,使用 :自定义名称="$attrs.想要的传来的属性名" eg: :style="$attrs.style"
  4. $attrs其实就是一个对象,用来接收传来的所有属性
  5. 使用inheritAttrs:false,不接受父组件传来的属性
<script>
app.component("box",{
  // props:["msg"],
  // 不接受no-props属性
  // inheritAttrs:false,
  template:`
  <div :s1="$attrs.msg">我是全局子组件</div>
  <div  v-bind="$attrs">我是全局子组件</div>
  `,
  </script>
})

完结了这篇张,纪念一下,🍺🍺🍺,

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值