为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

课程章节: Composition API

主讲老师: Dell

课程内容:

今天学习的内容包括:

ref,reactive响应式的引用原理:通过proxy对数据进行封装,当数据变化时,触发模板等内容的更新。

ref处理基本数据类型:proxy,变成proxy({value:’’})这样的一个响应式的引用

reactive处理非基本数据类型:proxy,变成proxy({name:’’})这样的一个响应式的引用

ref:将简单类型的数据变成响应式

reactive:将数组、对象变成响应式

toRefs:将响应式的对象(proxy({ name: ‘abc’ })),转变成 { name: proxy({ value: ‘abc’ }) },这样对name进行解构操作,name也是响应式的。若在其上取不存在的属性,获取的是undefined

toRef:在对象上取不存在的属性时,找不到的话不会像toRefs一下拿到的是undefined,而是给这个属性一个默认的空值(不推荐使用)

attrs:None-Props 属性

slots:插槽,获取到slot.defaul

emit:相当于传统语法中的this.$emit的作用

watch 侦听器
1、具有一定的惰性,只有变化时才执行
2、参数可以拿到当前值和原始值。watch(侦听内容, (当前值,原始值)=> {…})
3、watch侦听的是getter/effect函数、ref、响应式对象、或者这些类型的数组
4、若侦听的是reactive类型, 变为函数。如watch( () => nameObj.name, (cur, per) => {…} )
5、侦听多个数据 。如 watch( [() => obj.name, () => obj.age], ([nameCur, ageCur], [namePre, agePre]) => {…} )

watchEffect侦听器: watchEffect(()=> { … })
1、立即执行,没有惰性;
2、不需要传递需要侦听的内容,自动感知代码依赖;不需要传递多个参数,只需要传递一个回调函数
3、不能获取之前数据的值

课程收获:

6.1 心得:

为什么要用setup(),之前老语法在面对比较复杂的组件去开发的时候,数据,方法都是去分开写的,这就导致,维护,可读性差;

setup()何时去执行,beforecreate

之前像是methods,return {} 这些全部被setup()去包裹,那么如果你想要去使用一些数据,与方法,需要将这些内容,return出去,也就是说,暴露出去,组件就可以来使用这些内容了

this是不是指向的就是实例化的对象,但是由于,此时未实例化,所以,this 指向为空

但是当组件实例化完成之后,然后我就可以去调用setup() 了,因为setup在实例化完成之前,就创建好了

setup:created 实例被完全初始化之前执行的函数,所以用不了this

setup(props,context){

    return {

        name:‘dell’,

        handClick:()=> {

            alert(123)

        }

    }

}

6.2/6.3 心得:

ref、reactive 响应式的引用:

原理:通过 proxy 对数据进行封装,当数据变化时,触发模板等内容的更新

ref:处理基础类型的数据

const  { ref } = Vue;

//  proxy,‘dell’变成proxy({value:‘dell’}) 这样一个响应式引用

let name = ref(‘dell’);

name.value = ‘lee’;

reactive:处理非基础类型的数据

const  { reactive } = Vue;

//  proxy,{ name:‘dell’}变成proxy({ name:‘dell’}) 这样一个响应式引用

const  nameObject =reactive({ name:‘dell’});

nameObject.name = ‘lee’;

让数据只读 使用readonly() 函数
如果直接解构setup里reactive()的数组或者对象是在外面不可用的,因为reactive只是将数组/对象变成了响应式,但是没有将里面的每一项变成响应式,单独的只是一个字符串/数字等。
如果要想解构,需要用到toRefs()函数
他将proxy({name: 'cmy', age: '18' }) ===>

proxy({
name: proxy({ value: 'cmy' }),
age: proxy({value: 18})
})

外面可以直接引用name、age 相当于引用name.value、age.value

readonly:使响应式应用只读,不可修改

const copyName = readonly(nameObj);

toRefs:可以进行解构(reactive无法进行解构)

//  proxy({ name:‘dell’})  =>  { name:proxy({ value:‘dell’})}

const { name } = toRefs(nameObj);

return { name }

6.4/6.5 心得

toRefs() 如果引用的数据里面没有某个字段,他不会给默认值,而是会说明该字段是undefined
如果不想要避免这种情况,可以使用toRef()函数。使用如下图,它会使不存在的也具有响应式
但不建议使用该方法,也不建议使用添加数据中没有的字段,若要使用,就在数据中心添加该字段,给一个空值。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root"></div>
</body>
<script>
//ref,reactive 响应式的引用
//原理,通过proxy对数据进行封装,当数据变化时,出发模板等内容的更新
//ref 处理基础类型的数据,如字符串,数字等(不适合数组对象等)
//reactive 处理非基础类型的数据
const app = Vue.createApp({
template: `
           <div>{{nameArray[0]}}</div>
       `,
setup(props,context) {
// const { ref } = Vue
// //proxy,'dell'变成 proxy({value:'dell'})这样的响应式引用
// let name = ref('dell');
// setTimeout(() => {
//     name = 'lee'
// }, 2000);
// return { name }
// const { reactive } = Vue
// //proxy,'dell'变成 proxy({value:'dell'})这样的响应式引用
// let nameObj = reactive({name:'dell'});
// setTimeout(() => {
//     nameObj.name = 'lee'
// }, 2000);
// return { nameObj }
// const { reactive } = Vue
// //proxy,'dell'变成 proxy(['dell'])这样的响应式引用
// let nameArray = reactive(['dell']);
// setTimeout(() => {
//     nameArray[0] = 'lee'
// }, 2000);
// return { nameArray }
const { reactive, toRefs } = Vue
//proxy,'dell'变成 proxy(['dell'])这样的响应式引用
let nameObj = reactive({name:'dell',age:23});
setTimeout(() => {
nameObj.name = 'lee'
}, 2000);
//toRefs proxy({ name:'dell',age:23})转化成{
//  name: proxy({ value: 'dell'}),
//  age: proxy({ value: 23})
// }
const { name } = toRefs(nameObj)
return { name }
//readOnly不允许修改
// const { readOnly } = Vue
// let nameReadOnly = readOnly(['dell']);
// setTimeout(() => {
//     nameReadOnly[0] = 'lee'
// }, 2000);
// return { nameReadOnly }
}
})
const vm = app.mount('#root')
</script>
</html>

6.5 心得:

setup(props,context){ }

context共有三个值 attrs,slots,emit

attrs 接收No-props属性

slots 是插槽, slots.defalut() 【例子如下图】他接收了父组件传来的值parent,以前的用法如mounted函数中的例子

emit: 代替this.$emit 子组件向外出发事件

const  { attrs,slots,emit }  =  context;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root"></div>
</body>
<script>
//toRef
const app = Vue.createApp({
methods: {
handleChange(){
alert('change')
}
},
template: `
           <child app="app" @change="handleChange">parent</child>
       `
});
app.component('child',{
template: `
           <div @click="handleClick">12122</div>
       `,
setup(props, context) {
const { h } = Vue
const { attrs, slots, emit } = context
console.log('attrs',attrs.app)
console.log('slots',slots.default())
//return () => h ('div',{},slot.default())
function handleClick() {
emit('change')
}
return { handleClick }
}
})
const vm = app.mount('#root')
</script>
</html>

6.6/6.7 心得:

reactive来定义非基础类型

 // 和list相关的代码
    const listRelative = ()=>{
        const {reactive} = Vue
        const list = reactive([])
        handleClick = (inputvalue)=>{
            if(inputvalue){
                list.push(inputvalue)
            }  
        }
        return {
            list,
            handleClick
        }
    }
    // 和输入框相关的代码
    const inputRef = ()=>{
        const {ref}= Vue
        const inputValue = ref('')
        handleInput = (e)=>{
            inputValue.value = e.target.value
        }
        return {
            inputValue,
            handleInput
        }
    }
    const app = Vue.createApp({
        template:`
            <div>
                <div>
                    <input :value="inputValue" @input="handleInput"/>
                    <button @click="handleClick(inputValue)">提交</button>
                </div>
                <ul>
                    <li v-for="(item,index) in list">{{item}}</li>
                </ul>
            </div>
        `,
        setup(){        
            const {list,handleClick} = listRelative()
            const {inputValue,handleInput} = inputRef()
            return {
                list,
                inputValue,
                handleInput,
                handleClick
            }
        }
    })
    const vm = app.mount('#root')

如果事件直接绑定函数名称,那么默认会传递事件对象作为事件函数的第一个参数;

如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递,并且事件对象的名称必须是$event;

6.8 心得:

具备get和set的计算属性

const app = Vue.createApp({
 setup() {
   const { reactive, computed } = Vue;
   const countObj = reactive({ count: 0});
   const handleClick = () => {
     countObj.count += 1;
   }
   let countAddFive = computed({
     get: () => {
       return countObj.count + 5;
     },
     set: (param) => {
       countObj.count = param - 5;
     }
   })

   setTimeout(() => {
     countAddFive.value = 100;
   }, 3000)

   return { countObj, countAddFive, handleClick }
 },
 template: `
   <div>
     <span @click="handleClick">{{countObj.count}}</span> -- {{countAddFive}}
   </div>
 `,
});

如果是只用get,则计算属性传入一个函数,

如果是要用get和set,则计算属性要传一个对象。

6.9/6.10 心得:

watch监听器:
具有一定的惰性 lazy (首次页面展示时不会执行)

参数可以拿到原始和当前值

setup(){

    const { ref,watch }  =  Vue;

    const name = ref(‘lee’);

    watch(name,(currentValue,preValue)=> {

            console.log(currentValue,preValue)

    })

    return { name }

}

监听reactive复杂类型的数据,需要用箭头函数的方式监听

setup(){

    const { reactive,watch }  =  Vue;

    const nameObj = reactive({ name:‘lee’ });

    watch(()=> nameObj name,(currentValue,preValue)=> {

            console.log(currentValue,preValue)

    })

    cosnt { name }  =  toRefs(nameObj);

    return { name }

}

可以侦听多个数据的变化,用一个侦听器承载(用数组来操作)

setup(){

    const { reactive,watch }  =  Vue;

    const nameObj = reactive({ name:‘lee’,englishName:‘dell’ });

    watch([()=> nameObj name,()=> nameObj englishName],( [curName,curEng],[ preName,preEng ] )=> {

            console.log(curName,preName,‘——’,curEng,preEng )

    })

    cosnt { name }  =  toRefs(nameObj);

    return { name }

}

watchEffect 侦听器,偏向于 effect (更适合异步的请求)

1、立即执行,没有惰性 immediate

2、不需要传递你要侦听的内容,自动会感知代码依赖,不需要传递很多参数,只要传递一个回调函数

3、不能获取之前数据的值

setup(){

    cosnt { watchEffect  } = Vue;

    watchEffect (()=>{

        console.log(nameObj.name)

        console.log(nameObj.englishName)

    })

}

停止监听器(watch和watchEffect通用)

setup(){

    cosnt { watchEffect  } = Vue;

    const  stop = watchEffect (()=>{

        console.log(nameObj.name)

        console.log(nameObj.englishName)

        setTimeout(()=>{

                stop();

        },5000)

    })

}

watch也可以做非惰性的监听(配置{ immediate:true })

setup(){

    const { reactive,watch }  =  Vue;

    const nameObj = reactive({ name:‘lee’,englishName:‘dell’ });

    watch([()=> nameObj name,()=> nameObj englishName],( [curName,curEng],[ preName,preEng ] )=> {

            console.log(curName,preName,‘——’,curEng,preEng )

    },{ immediate:true })

    cosnt { name }  =  toRefs(nameObj);

    return { name }

}

6.11 心得:

beforeMount => onBeforeMount

mounted => onMounted

beforeUpdate => onBeforeUpdate

beforeUnmount => onBeforeUnmount // 组件从页面移除的时候执行该方法

unmounted => onUnmounted // 组件从页面移除之后执行该方法

setup的生命周期中没有beforeCreate,created两个函数,因为setup执行的时间就在这两个函数之间

新的生命周期:

onRenderTracked:每次渲染之后重新收集响应式依赖的时候会自动执行的函数

onRenderTriggerd:每次触发页面重新渲染时候自动执行的函数
setup中生命周期函数的写法

const app = Vue.createApp({
 // beforeMount => onBeforeMount
 // mounted => onMounted
 // beforeUpdate => onBeforeUpdate
 // beforeUnmount => onBeforeUnmount
 // unmouted => onUnmounted
 setup() {
   const {
     ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated,
     onRenderTracked, onRenderTriggered
   } = Vue;
   const name = ref('dell')
   onBeforeMount(() => {
     console.log('onBeforeMount')
   })
   onMounted(() => {
     console.log('onMounted')
   })
   onBeforeUpdate(() => {
     console.log('onBeforeUpdate')
   })
   onUpdated(() => {
     console.log('onUpdated')
   })
   // 每次渲染后重新收集响应式依赖
   onRenderTracked(() => {
     console.log('onRenderTracked')
   })
   // 每次触发页面重新渲染时自动执行
   onRenderTriggered(() => {
     console.log('onRenderTriggered')
   })
   const handleClick = () => {
     name.value = 'lee'
   }
   return { name, handleClick }
 },
 template: `
   <div @click="handleClick">
     {{name}}
   </div>
 `,
});

生命周期函数的新写法 ,beforeCreate ,created 没有新写法。因为setup()执行在他俩之间

6.12 心得:

const app = Vue.createApp({ 

	setup(){

		const{ provide }= Vue; 

		provide('name', 'dell'); 

		return {}

},

template: 

	<div> 

		<child/> 

	</div> 

});

app. component('child',{ 

	setup(){

	const { inject }= Vue;

	const name = inject('name', 'hello'); 

	return { name }

},

	template: '<div>{{name}}</div>' 

})

单向数据流:谁的值由谁更改(子组件不能更改父组件的数据)

父组件传递方法:

const app = Vue.createApp({ 

	setup(){

		const { provide, ref }= Vue;

		const name = ref('dell'); 

		provide('name', name);

		provide('changeName',(value) => { 

			name.value = value;

})

	return{} 

},


子组件调用父组件的方法:

app.component('child',{

setup(){

	const { inject }=Vue; 

	const name = inject('name');

	const changeName = inject('changeName'); 

	const handleClick=()=>{

		changeName('Lee'); 

}

	return { name, handleClick} 

},

	template: '<div @click="handleClick">{{name}}</div>' 

想要获取ref绑定的dom,需要const hello = ref(null),再由hello.vue获取到dom

// CompositionAPI 的语法下,获取真实的 DOM 元素节点 

const app = Vue.createApp({

	setup(){

		const { ref, onMounted}=Vue;

		const hello = ref(null);

		onMounted(() => {

		console.log(hello.value); 

})

		return { hello0 } 

},


图片描述

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消