手记

【学习打卡】第3天 【2022版】Vue3 系统入门与项目实战第三讲

课程名称: 2022持续升级 Vue3 从入门到实战 掌握完整知识体系

课程章节: 探索组件的理念

主讲老师: Dell

课程内容:

今天学习的内容包括:
组件:根组件在实例里面写,子组件在实际例外面通过components创建。
组件具备复用性;
组件分为:全局组件和局部组

课程收获:

3.1/3.2 心得:

全局组件不用时也会挂载在APP上 ,处处可以调用,性能不高,使用简单

  1. 全局组件:只要定义了,处处可以使用(子组件使用子组件,父组件使用子组件),性能不高,但是用起来简单;

    名字建议: 小写字母单词,多个字母中间用横线分隔例如hello-world

  2. 局部组件: 定义了,要在Vue.createApp({})中用components{}注册才能使用,性能比较高,使用起来有些麻烦;

    名字建议: 驼峰式命名;例如HelloWorld;单个单词首字母大写,以便区分局部组件和普通常量

    注意: 局部组件使用时,要做一个名字和组件间的映射对象,如果组件用的名字和定义的名子相同,不做映射,Vue底层也会自动尝试做映射,否则必须做映射。

	components:{  counter:Counter }

3.4 心得:

组件间传值:静态传值和动态传值

静态传值:

  1. 组件上写传值名称和要传的值,例如 content=“123”;
  2. 子组件通过props接收, 例如:props: [‘content’].
  3. 简单但有限制,只能传来string类型

动态传值:

  1. 要在传值名称前加v-bind,传的值是个变量; 例如:v-bind:content=“message”(message变量在data中定义)
  2. 子组件通过props接收。
  3. 灵活且种类不限制。 String,Boolean,Array, Object, Function, Symbol都可以。

传值校验

  1. 只种类校验的话在 props: { content: Number } 直接写想要传的类型,如果传的不对页面依旧展示但是会警告
    列表项
  2. type:校验类型
  • default: 默认值(没有传值时,展示默认值,可以是函数)function() { … }
  • required: bool值—true:必须有值
  • validator: function(value) { … } 深度校验(value是传来的值)是否符合想要的特性
    例如:
	props: {  
		content: {
		type: ...,  
		required: ...,  
		default: ...,
		validator: function(value) { ... } 
		} 
	}

props接受父组件传值,可以用数组和对象来接收,在对象里面,接收数据的类型可以是:Number String Boolean Array Object Function Symbol;
props接收的值也可以写的更加详细,这个值可以用一个对象来接收,写明具体的类型,是否必须传指定类型;

3.5 心得:

组件间传值传递多个值
前置条件: data中有 a, b, c等多个数据; 有个子组件为 demo
简写前:要传递多个值时,需要挨个写要传递属性 ,例如 <demo :a=“a” :b=“b” :c=“c” … />
简写后:可以将要传递的多个值放到一个对象里,例如:obj: { a: 123, b: 234, c: 345 };然后传递属性时只需要 v-bind=“obj”, 在子组件的props中接收[‘a’, ‘b’, ‘c’] ;例如 , 相当于 <demo :a=“obj.a” :b=“obj.b” :c=“obj.c” … />

在 html 标签上的属性名称太长
建议使用短横线(-)来连接单词(例如:),vue标签是不支持驼峰式的语法的。
注意:子组件接收时要用驼峰式,(例如props:[‘dataTime’])

单向数据流:
子组件可以使用父组件传过来的数据,但不能修改该数据。因为如果可以修改,在其他地方引用该数据也会因为改变而改变,会引起逻辑错误和混乱
如果要改变,可以自定义一个变量,让它的值等于传过来的值,修改自定义的值

父组件向子组件传多个值时简写:v-bind=“params”
// 父组件

data(){
	return {
		params:{
			content:1234,
			a:123,
			b:456,
			c:789
		}
	}
},
template:`<div><test  v-bind="params"  /></div>`

属性传的时候,使用 content-abc 这种命名,接的时候,使用contentAbc 命名

3.6 心得:

Non-prop属性:父组件向子组件传递内容,子组件没有用props来接收 ( 可适用于样式传递 )。Vue底层会把父组件传递给子组件的内容放在子组件最外层的dom标签上。

  1. 该情况适用于子组件只有一个根节点
  2. 当子组件有多个根节点时,父组件的Non-prop属性就不会生效
// 父组件

const app = Vue.createApp({

    template:`<div><counter  ></div> `

})

// ①  子组件(子组件只有一个根节点)

app.component( 'counter', {

    template: ` <div> Counter </div> `

} );

//   浏览器    Counter 显示为红色字体 

<div > Counter </div>   



// ② 子组件(子组件有多个根节点)

app.component( 'counter', {

    template: ` 

        <div> Counter1 </div>

        <div> Counter2 </div>

        <div> Counter3 </div>

     `

} );

//  浏览器  Counter无任何样式

<div> Counter1 </div>

<div> Counter2 </div>

<div> Counter3 </div>

子组件不继承父组件的父组件的Non-prop属性 (子组件只有一个根节点)

当子组件设置inheritAttrs:false时,就可以让子组件不继承父组件的Non-prop属性。

app.component( 'counter', {

    inheritAttrs: false,

    template: ` <div> Counter </div> `

} );

//  浏览器开发者工具 元素上显示

<div> Counter </div>

子组件选择性接收父组件的属性 (子组件有多个根节点)

  1. 在子组件的根节点上使用 v-bind="$attrs" 可接收所有父组件传过来的内容,
  2. 使用 :msg="$attrs.msg" 可以接收指定的内容。
  3. 在子组件内也可以用 this.$attrs 来获取父组件 Non-prop 的属性。
// 父组件

const app = Vue.createApp({

    template:`<div><counter    msg="hello"  msg1="world"></div> `

})



// 子组件 第一种情况

app.component( 'counter', {

    mounted() {

        console.log( this.$attrs );  // 第三种情况

    },

    template: ` 

        <div  v-bind="$attrs"> Counter1 </div>  // 第一种情况

        <div  :msg="$attrs.msg"> Counter2 </div>   // 第二种情况

     `

} );

//  浏览器  Counter无任何样式

<div    msg="hello"  msg1="world"> Counter1 </div>

<div  msg="hello" > Counter2 </div>

传递所有的参数从父组件到子组件:v-bind:params
传递所有的属性到子组件中的某一个节点: v-bind:’$attrs’

3.7/3.8 心得:

组件间通过事件通信:

  1. 子组件通过 this.$emit() 来向外触发事件,可带参数(事件,参数1, … )
  2. 传递的方法是驼峰式命名,接收用“-”分隔, 并用@监听
    例如子组件方法里用 this.$emit(‘addOne’) 向父组件传递,父组件通过@add-one="handleAddOne"接收, 传递参数的时候,父组件方法里可以接收

子组件字段 emits

  1. 可以是数组 [ ], 也可以是对象 { } ;
  2. 书写要向父组件传递的事件方法名称,以便清楚知道都传了哪些事件,不容易混乱。
  3. {}里可以写方法,对事件触发的参数进行校验,是否满足自己的需求,不满足发警告
//  父组件

data() {

    return { count: 1 }

},

methods: {

    handleAddOne( param ) {

        this.count += param

    }

},

template: `

    <div>

        <counter :count="count" @add-one="handleAddOne" />

    </div>

`

// 子组件  counter

props: [ 'count' ],

// emits: [ 'addOne' ],  // 数组

emits: {  // 对象

    addOne: ( count ) => {   // 对传递的参数进行判断是否符合预期

        if( count > 0 ) return true ;

        return false ;

    }

},

methods: {

    handleClick () {

        this.$emit( 'addOne',  1 );

    }

},

template: `

    <div @click="handleClick" > {{ count }} </div>

`

modelValue:

使用条件:

  1. 父组件的数据通过 “v-model” 传递给子组件
  2. 子组件接收的props名字必须是 “modelValue”
  3. 子组件向外传递事件的名字必须是 “update:modelValue”

如果不想使用 “modelValue” ,那么可以在父组件传递数据时写成 “v-model:name”,子组件在接收props时也应该用的是 “name” ,子组件向外传递事件的名字也要变成 "update:name"就可以了。

若子组件只是改变父组件传来的值,emit 方法类似于 v-model 的方式

vue 中可以将这种简化利用 v-model 来实现

// 父组件

data() {

    return { count: 1 }

},

// template: ` <counter v-model="count" /> `  

// 若想将接收的参数改成自定义名字 则 v-model:count  count为自定义的名字

template: ` <counter v-model:count="count" /> `  



// 子组件

// props: [ 'modelValue' ],     // 接收参数的名称固定为 modelValue,不可以为其他名称  

props: [ 'count' ],  // 在这里就可以接收成count 

methods: {

    handleClick() {

        // 事件 update: modelValue 为固定写法

        // this.$emit( 'update: modelValue',  this.modelValue + 3 ) ;

        this.$emit( 'update: count',  this.count + 3 ) 

    }

},

// template: ` <div @click="handleClick"> {{ modelValue }} </div> `

template: ` <div @click="handleClick"> {{ count }} </div> `

3.9 心得:

若需要使用多个v-model来传递数据,需要使用 v-model:name 的形式。

// 父组件

<Counter v-model:count1="count" v-model:count2="count2"  />、

// 子组件

props: [ 'count1', 'count2' ]

在非form表单元素上使用v-model后的自定义的修饰符
注: v-model 仅限在 form 表单里加系统自带的修饰符

// 父组件  v-model 加自定义修饰符 uppercase

    <Counter v-model.uppercase="count" />


// 子组件 modelModifilers :指的是传递过来的修饰符, 名称是默认的不可更改

props: {

    modelValue: String,

    modelModifiers: {   

    default: () => {}    // 若没有传递修饰符,则modelModifiers 为空对象

  }

}, 

 //  在该示例中 modelModifiers为 { uppercase:true }

methods: {
  handleClick () {
    let newValue = this.modelValue + 'b'
    if (this.modelModifiers.uppercase) {      // 可以结合修饰符来将参数做处理
      newValue = newValue.toUpperCase()
    }
    this.$emit('update:modelValue', newValue)
  }
}


若需要使用多个v-model来传递数据,需要使用 v-model:childName=“parentName” 的形式。

<Counter v-model:count="count" v-model:count2="count2"  />

3.10/3.11 心得:

slot 插槽

  1. 放在调用子组件内部的东西 ,
  2. 插槽内可以包含任何模板代码,包括 HTML、甚至其它的组件
  3. 如果子组件的 template 中没有包含一个 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。
  4. slot插槽是不能绑定事件的,如果需要绑定事件可以i在slot的外层加个标签进行事件绑定。

示例中 myform(子组件) 标签中的 提交 就是要插在子组件中的东西

// 父组件

template:`<myform> <button> 提交 </button> </myform>`

// 子组件 myform
template: `
   <div>
     <input />
     <solt></solt>    
   </div>
 `

//  浏览器界面显示:一个 input 输入框 , 一个提交的 button 按钮

slot的数据使用,作用域问题

在父模板里使用数据就调用父模板里的数据

在子模板里使用数据就调用子模板里的数据

父组件如果想向子组件传递一些dom节点,或者元素标签(字符串、子组件都可以传递)的时候,直接把元素写在标签中就可以,子组件调用这些标签用slot就可以

具名插槽: 将一个slot拆成多个具名插槽,使标签、dom的传递更加灵活

<layout>
<template v-slot:header>header</template> <!-- 具名插槽指定标签类型不能渲染 -->
<template v-slot:footer>footer</template>
</layout>

app.component('layout', {
template: `
<div>
<slot name="header"></slot>
<div>content</div>
<slot name="footer"></slot>
</div>
`
}

<slot></slot> 插槽用来替换父组件当中的内容

slot 作用域:父模板的数据调用父组件里的 data,子模板的数据调用子组件里的 data。

插槽中间可以添加 default value;

3.12 心得:

具名插槽的简写方法 在template标签中 #插槽名

<template  #header>

        <div>header</div>

</template>

vue:插槽

父组件向子组件传递dom元素时,不用props传递,用插槽实现,子组件用接收父组件传递的dom内容;

传递动态dom内容<div>{{text}}</div> <slot>default value</slot>默认值设定

<layout>
  <template v-slot:header #header>
     <div>header</div>
   </template>
   <template v-slot:footer #footer>
       <div>footer</div>
   </template>
</layout>

app.component('layout',{
  template: `
      <div>
          <slot name="header"></slot>
          <div>content</div>
          <slot name="footer"></slot>
      </div>
  `
})

作用域插槽:父组件调子组件的时候传slot进来,子组件再通过属性的形式,把数据传给子组件,父组件拿到内容时再显示
当子组件渲染的内容要由父组件决定的时候,可以使用作用域插槽,可以把父组件的item数据从子组件传递过来,父组件从理论上就可以调用子组件的数据

<list v-slot="slotProps">
   <span>{{slotProps.item}}</span>
</list>
<list v-slot="{item}">
   <span>{{item}}</span>
</list>
app.component('list', {
  data() {
    return { list: [1,2,3]}
  },
  template: `<slot v-for="item in list" :item="item"></slot>`
})

3.13 心得:

动态组件:根据数据的变化,结合 component 这个标签,来随时动态切换组件的显示 (component+:is)

keep-alive:缓存作用
keep-alive 动态组件缓存,当动态组件input框中输入内容后,点击切换默认是清空内容的,当需要保存输入的内容时 可以将动态组件用 keep-alive 标签包裹

<keep-alive>

        <component  :is=‘currentItem’ />

</keep-alive>

异步组件:异步执行某些组件的逻辑 Vue.defineAsyncComponent(()=> { return new Promise((res,rej)=>{})})

slot无法直接绑定标签

父模板里调用的数据属性,使用的都是父模板里的数据

子模板里调用的数据属性,使用的都是子模板里的数据

在标签中输入内容,是slot的默认值

具名插槽:将一个slot拆成多个具有插槽,是标签、dom的传递更加灵活

使用具名插槽v-slot要配合标签使用,不能在dom标签上使用

v-slot: 可以简写为#

作用于插槽,可以使父组件使用子组件的数据

app.component('async-common-item', Vue.defineAsyncComponent(() => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve({
          template: `<div>this is an async component</div>`
        })
      }, 5000)
    })
  }))

3.14 心得:

v-once:让某个元素标签只渲染一次

ref:实际上是获取Dom节点/组件引用的一个语法 (在标签上用ref绑定,获取时为this.$refs.xxx)

ref也可以在父组件上获取子组件的方法

provide、inject:多层组件传值
provide想传递给其他组件自己的data值需要变成函数,但是只能传递一次,当其自身的data值改变时,不会再传给其余组件
provide提供的数据是一次性的,不是响应式的,不是双向绑定的,inject拿到的永远是第一次传的值

// 父组件向孙子组件传递参数 provide写法
// 需要注意的是,这里传递的值不是响应式的,始终只是第一次传递过去的值。例第一次传递了数字1,就算父组件里面的方法改变了 num 的数值,孙子组件里面还是显示1
provide{
count: 1
}
// 如果 provide 想传递 data 里面的变量
data(){ return { num: 1} },
provide(){
return {
count: this.num
}
}
// 孙子组件
inject: ['count']


0人推荐
随时随地看视频
慕课网APP