vue3 基础入门知识

setup函数

setup 函数是一个新的组件选项, 作为组件中 compositionAPI 的起点
从生命周期角度来看, setup 会在 beforeCreate 钩子函数之前执行
setup 中不能使用 this, this 指向 undefined
在模版中需要使用的数据和函数,需要在 setup 返回。

reactive函数

1.setup需要有返回值,只有返回的值才能在模板中使用

2.默认普通的数据,不是响应式的

作用:

通常是用来自定义响应式对象数据

ref函数

reactive处理的数据,必须是复杂类型,如果是简单类型无法处理成响应式,所以有ref函数

作用:

对传入的数据(一般简单数据类型),包裹一层对象,转换成响应式

  1. ref函数接收一个的值,返回一个ref响应式对象,有唯一的属性value,指向该初始值

  2. 在setup函数中,通过ref对象的value属性,可以访问到值

  3. 在模块中,ref属性会自动解套,不需要额外的value

  4. ref函数也支持传入复杂类型,传入复杂类型,也会做响应式处理

ref和reactive的最佳属于方式

明确的对象,明确的属性,用reactive,其他用ref

ref函数的作用:处理响应式数据 使用ref处理的数据在setup中需要value

reactive的作用:处理复杂数据类型的响应式

reactive函数

返回普通对象的响应式副本 参数为需要定义为响应式数据的数据对象,可以理解为相当于vue2中的data

如果希望直接使用data中的属性,一般我们会用es6的解构赋值,但直接将data解构,那么data中的数据就不再具有响应式的特性

setup() {
    const data = reactive({
        name: 'zhangsan',
        age: 0
    })
    return {
        data   // 组件中使用data中的属性时需要使用data[key]的方式使用,例如组件中使用name应该写成data.name
    }
}

unref函数

参数是ref,则返回参数的value,否则直接返回参数本身

const count = ref(2)
unref(count)   // 2
const str = '111'
unref(str)     // '111'

toRefs函数

讲响应式对象转换为普通对象,其中结果对象的每个property都是指向原始对象相应property的ref,那么再将结果对象结构赋值的时候,属性的响应式特性会保留

setup() {
    const data = reactive({
        name: 'zhangsan',
        age: 0
    })
    return {
        ...toRefs(data)            // 组件中可以直接使用data中的属性,且为响应式
    }
}

toRef函数

可以用来为源响应式对象的某个property新创建一个ref。ref可以被传递,它会保持对其源property的响应式连接

setup() {
    const data = reactive({
        num: 1
    })
    const count = toRef(data, 'num')
    const changeCount = () => {
        count.value += 1  
    }
    console.log(data.num)          //  2
    return {
        count      // 组件中可以直接使用count,且为响应式
    }
}

toRaw和markRaw方法

/*
---toRaw--
toRaw() 作用是将一个由 reactive 或 readonly  生成的响应式对象转为普通对象,作用类似于返回最原始的对象
这是一个还原方法,可用于临时读取,访问不会被代理/跟踪,写入时也不会触发界面更新。
person是一个响应式对象,通过toRaw(person)得到的user,是一个普通对象,不再是一个响应式对象。
更改user.age的值时,页面不会更新。
只有更改person.age的值时,页面才会更新。
*/
 var person = reactive({
      name: "long",
      age: 23,
    });
    var user = toRaw(person);
    var change = () => {
      user.age++;
      console.log(user)
    };
    return {
      user,
      person,
      change,
    };
​
/*
    ---markRaw---
markRaw 作用是标记一个对象,使其永远不会再成为响应式对象
person是一个响应式对象,
通过person.likes=likes,往person中添加的属性,那么这个新添加的属性likes也会是响应式的。
如果通过person.likes= markRaw(likes),往person中添加的属性,那么likes被标记为不是响应式的,那么这个新添加的属性就不是响应式的,更改它的值不会更新页面。
*/
  setup() {
    var person = reactive<UserInfo>({
      name: "long",
      age: 23,
    });
    var likes = ['吃饭','睡觉'];
    person.likes = markRaw(likes);
    var change = () => {
      person.likes[0] += '==';
      console.log(person.likes);
    };
    return {
      person,
      change,
    };
  },

script setup语法(*)

script setup是在单文件组件(SFC)中使用组合式API的编译时语法糖 相比于普通的script语法更加简洁
要使用这个语法,需要将 setup attribute 添加到 <script> 代码块上:
​
<script setup>
console.log('hello script setup')
</script>
顶层的绑定会自动暴露给模板,所以定义的变量,函数和import导入的内容都可以直接在模板中直接使用
​
<template>
  <div>
    <h3>根组件</h3>
    <div>点击次数:{{ count }}</div>
    <button @click="add">点击修改</button>
  </div>
</template>
​
<script setup>
import { ref } from 'vue'
​
const count = ref(0)
const add = () => {
  count.value++
}
</script>

计算属性computed函数

computed函数调用时,要接收一个处理函数,处理函数中,需要返回计算属性的值

<template>
  <div>我今年的年纪 <input type="text" v-model="age" /></div>
  <div>我明年的年龄 {{ nextAge }}</div>
  <div>我后年的年龄 <input type="text" v-model="nextAge2" /></div>
</template>
​
<script setup>
import { computed, ref } from 'vue'
const age = ref(10)
// 不带set的计算属性
const nextAge = computed(() => {
  return +age.value + 1
})
​
// 带set的计算属性
const nextAge2 = computed({
  get() {
    return +age.value + 2
  },
  set(value) {
    age.value = value - 2
  },
})
</script>

watch函数与wacthEffect函数

wacth函数与wacthEffect函数都是监听器,在写法和用法上有一定的区别,是同一种功能的两种不同形态,底层都一样

watch和watchEffect的对比
watch
  • watch显式指定依赖数据,依赖数据更新时执行回调函数

  • 具有一定的惰性lazy 第一次页面展示的时候不会执行,只有数据变化的时候才会执行(设置immediate: true时可以变为非惰性,页面首次加载就会执行)

  • 监视ref定义的响应式数据时可以获取到原值

  • 既要指明监视的属性,也要指明监视的回调

watchEffect
  • watchEffect自动收集依赖数据,依赖数据更新时重新执行自身

  • 立即执行,没有惰性,页面的首次加载就会执行

  • 无法获取到原值,只能得到变化后的值

  • 不用指明监视哪个属性,监视的回调中用到哪个属性就监视哪个属性

watch函数
  1. 参数1:监视的数据源

  2. 参数2:回调函数

  3. 参数3:额外的配置

// 监听单个ref
const money = ref(100)
watch(money, (value, oldValue) => {
  console.log(value)
})
​
// 监听多个ref
const money = ref(100)
const count = ref(0)
watch([money, count], (value) => {
  console.log(value)
})
​
// 监听ref复杂数据
const user = ref({
  name: 'zs',
  age: 18,
})
watch(
  user,
  (value) => {
    console.log('user变化了', value)
  },
  {
    // 深度监听,,,当ref的值是一个复杂数据类型,需要深度监听
    deep: true,
    immediate: true
  }
)
​
// 监听对象的某个属性的变化
const user = ref({
  name: 'zs',
  age: 18,
})
watch(
  () => user.value.name,
  (value) => {
    console.log(value)
  }
)
深度解析watch函数

watch函数有两个小坑:

  • 监视reactive定义的响应式数据(该数据为一个对象,因为reactive只能定义数组或对象类型的响应式)时:oldValue无法正确获取,会强制开启深度监视,deep配置不生效。

  • 监视reactive定义的响应式数据中的某个属性时,且该属性是一个对象,那么此时deep配置生效

具体的watch函数的用法在下面代码中都有所体现,注释详细

<template>
    <div>
        <h2>当前求和为:{{sum}}</h2>
        <button @click="sum++">点我+1</button>
        <hr>
        <h2>当前的信息为:{{msg}} </h2>
        <!-- 点击button拼接! -->
        <button @click="msg+='!'">修改数据</button>
        <hr>
        <h2>姓名:{{person.name}}</h2>
        <h2>年龄:{{person.age}}</h2>
        <h2>薪资:{{person.job.j1.salary}}</h2>
        <button @click="person.name+='~'"> 修改姓名</button>
        <button @click="person.age++"> 增长年龄</button>
        <button @click="person.job.j1.salary++"> 增长薪资</button>
    </div>
</template>
​
<script>
import {ref,reactive,watch,watchEffect} from 'vue'
export default {
   name:'demo',
   setup(){
       //数据
       let sum = ref(0)
       let msg = ref('hello')
       let person = reactive({
           name:'zhangsan',
           age:'18',
           job:{
               j1:{
                   salary:20
               }
           }
       })
       //监视(三个参数,第一个是监视的对象,第二个是监视的回调函数,第三个是监视的配置)
​
       //情况一:监视ref所定义的一个响应式数据
       watch(sum,(newValue,oldValue)=>{
           console.log('sum的值变化了',newValue,oldValue)
       },{immediate:true,deep:true})
       //immediate的值为true时表示非惰性的立即执行的(默认情况下是false)
       //deep深层次触发(此处设置deep无意义)
​
       //情况二:监视ref所定义的多个响应式数据,写成数组的形式
​
       watch([sum,msg],(newValue,oldValue)=>{
           console.log('sum或者msg变了',newValue,oldValue)
       })
​
       //情况三:监视reactive所定义的响应式数据
                //若监视的是reactive定义的响应式数据,则无法正确获得oldValue
                //若监视的是reactive定义的响应式数据,则watch会强制开启深度监视
​
        //我们发现改变person的任意一个属性都会被监视到
        watch(person,(newValue,oldValue)=>{
            console.log('person改变了',newValue,oldValue)
        }) 
        
        //我们尝试设置deep:false,关闭深度监听(目的:改变job的值不会被watch监听到)
        //但是我们发现deep:false并没有生效,原因是此时watch监视的是reactive定义的响应式对象,默认强制开启了深度监听
        watch(person,(newValue,oldValue)=>{
            console.log('person改变了',newValue,oldValue)
        },{deep:false}) 
        
​
​
      //情况四:监视reactive所定义的响应式数据中的某个属性
       watch(()=>person.name,(newValue,oldValue)=>{
            console.log('person的job改变了',newValue,oldValue)
        })
         watch(()=>person.age,(newValue,oldValue)=>{
            console.log('person的job改变了',newValue,oldValue)
        })
        watch(()=>person.job,(newValue,oldValue)=>{
            console.log('person的job改变了',newValue,oldValue)
        })
        //从上边我们发现改变name,age都会触发监听,但是改变job不会
        //这是因为name和age属性的值只是一个简单的基本类型数据,
        //而job属性的值是一个对象,比较深,想要监视到,就要开启深度监视,程序如下:
        watch(()=>person.job,(newValue,oldValue)=>{
            console.log('person的job改变了',newValue,oldValue)
        },{deep:true})//此时job改变,会被监视到,此处的deep配置生效
        //需要和情况三进行区分,此处watch监视的是reactive所定义的对象中的某个属性,而情况三watch监视的是reactive所定义的对象
​
      //情况五:监视reactive所定义的响应式数据中的某些属性,写成数组的形式
        watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
            console.log('person的name或age改变了',newValue,oldValue)
        })
​
       //返回一个对象(常用)
       return{
           sum,
           msg,
           person
       }
   }
}
</script>
​
watch取消监听
const stop1 = watch(
  [() => nameObj.name, () => nameObj.name],
  ([curName, curEng], [prevName, curEng]) => {
    console.log(curName, curEng, "----", prevName, curEng);
    setTimeout(() => {
      stop();
    }, 5000);
  }
);
深度解析watchEffect函数

函数用法如下代码所示,注释详细:

<template>
    <div>
        <h2>当前求和为:{{sum}}</h2>
        <button @click="sum++">点我+1</button>
        <hr>
        <h2>当前的信息为:{{msg}} </h2>
        <!-- 点击button拼接! -->
        <button @click="msg+='!'">修改数据</button>
        <hr>
        <h2>姓名:{{person.name}}</h2>
        <h2>年龄:{{person.age}}</h2>
        <h2>薪资:{{person.job.j1.salary}}</h2>
        <button @click="person.name+='~'"> 修改姓名</button>
        <button @click="person.age++"> 增长年龄</button>
        <button @click="person.job.j1.salary++"> 增长薪资</button>
    </div>
</template>
​
<script>
import {ref,reactive,watch,watchEffect} from 'vue'
export default {
   name:'demo',
   setup(){
       //数据
       let sum = ref(0)
       let msg = ref('hello')
       let person = reactive({
           name:'zhangsan',
           age:'18',
           job:{
               j1:{
                   salary:20
               }
           }
       })
//watchEffect函数内部所指定的回调中用到的数据只要发生变化,就会重新执行回调
//只有一个参数,就是回调
    watchEffect(()=>{
        const x1 = sum.value//因为sum是ref定义的响应式数据,需要使用.value调用
        const x2 = person.age
        console.log('watchEffect配置的回调执行了')
    })
           return{
           sum,
           msg,
           person
       }
   }
}
</script>
​
watchEffect取消监听
const stop = watchEffect(() => {
  console.log(nameObj.name);
  setTimeout(() => {
    stop();
  }, 5000);
});
watchEffect与computed

watchEffect与computed有点像:

  • 但是computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。

  • 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。

  • computed若是值没有被使用时不会调用,但是watchEffect始终会调用一次

举例:

<template>
    <div>
        <h2>当前求和为:{{sum}}</h2>
        <button @click="sum++">点我+1</button>
        <hr>
        <h2>当前的信息为:{{msg}} </h2>
        <!-- 点击button拼接! -->
        <button @click="msg+='!'">修改数据</button>
        <hr>
        <h2>姓名:{{person.name}}</h2>
        <h2>年龄:{{person.age}}</h2>
        <h2>薪资:{{person.job.j1.salary}}</h2>
        <button @click="person.name+='~'"> 修改姓名</button>
        <button @click="person.age++"> 增长年龄</button>
        <button @click="person.job.j1.salary++"> 增长薪资</button>
    </div>
</template>
​
<script>
import {ref,reactive,watch,watchEffect, computed} from 'vue'
export default {
   name:'demo',
   setup(){
       //数据
       let sum = ref(0)
       let msg = ref('hello')
       let person = reactive({
           name:'zhangsan',
           age:'18',
           job:{
               j1:{
                   salary:20
               }
           }
       })
       let person1 = reactive({
           firstName:'张',
           lastName:'三'
       })
       //computed
       //计算属性——简写(没有考虑计算属性被修改的情况)
       person1.fullName = computed(()=>{
           //必须含有返回值
           return person1.firstName+'-'+person1.lastName
       })
​
       //计算属性——完整写法(考虑读和写)
       person1.fullName = computed({
           //必须含有返回值
           get(){
               return person1.firstName+'-'+person1.lastName
           },
           set(value){
               const nameArr = value.split('-')
               person1.firstName = nameArr[0]
               person1.lastName = nameArr[1]
           }
       })
       //watchEffect
        //可以不写给返回值
        watchEffect(()=>{
            const x1 = sum.value//因为sum是ref定义的响应式数据,需要使用.value调用
            const x2 = person.age
            console.log('watchEffect配置的回调执行了')
        })
         return{
           sum,
           msg,
           person,
           person1
       }
   }
}
</script>
​

钩子函数的作用

Vue3的生命周期

1、setup() : 开始创建组件之前,在 beforeCreate 和 created 之前执行,创建的是 data 和 method

2、onBeforeMount() : 组件挂载到节点上之前执行的函数;

3、onMounted() : 组件挂载完成后执行的函数;

4、onBeforeUpdate(): 组件更新之前执行的函数;

5、onUpdated(): 组件更新完成之后执行的函数;

6、onBeforeUnmount(): 组件卸载之前执行的函数;

7、onUnmounted(): 组件卸载完成后执行的函数;

8、onActivated(): 被包含在 <keep-alive> 中的组件,会多出两个生命周期钩子函数,被激活时执行;

9、onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行;

10、onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数。

Vue2和Vue3对比
Vue2和Vue3钩子变化不大,beforeCreate 、created 两个钩子被setup()钩子来替代
vue2           ------->      vue3
 
beforeCreate   -------->      setup(()=>{})
created        -------->      setup(()=>{})
beforeMount    -------->      onBeforeMount(()=>{})
mounted        -------->      onMounted(()=>{})
beforeUpdate   -------->      onBeforeUpdate(()=>{})
updated        -------->      onUpdated(()=>{})
beforeDestroy  -------->      onBeforeUnmount(()=>{})
destroyed      -------->      onUnmounted(()=>{})
activated      -------->      onActivated(()=>{})
deactivated    -------->      onDeactivated(()=>{})
errorCaptured  -------->      onErrorCaptured(()=>{})

组件通讯

props 是实现父组件向子组件传递信息,props的数据是只读的
父组件
<template>
  <div class="box">
    <h1>我是父组件</h1>
    <hr />
    <Child info="我是父组件参数" :money="money"></Child>
  </div>
</template>
​
子组件:需要使用到defineProps方法去接受父组件传递过来的数据
​
<script setup lang="ts">
//defineProps是Vue3提供方法,不需要引入直接使用
let props = defineProps(['info','money']); //数组|对象写法都可以
</script
全局总线事件:全局事件总线$bus可以实现兄弟之间的通讯
子组件1:接受子组件2传递的参数
​
<script setup lang="ts">
import $bus from "../../bus";
import { onMounted } from "vue";
//组件挂载完毕的时候绑定一个事件,受将接来兄弟组件传递的数据
onMounted(() => {
  $bus.on("money", (money) => {
    console.log(car);
  });
});
</script>
​
子组件2:给子组件1传递参数
​
<script setup lang="ts">
import $bus from '../../bus';
//点击按钮回调
const handler = ()=>{
  $bus.emit('money',{money:"1个w"});
}
</script>
v-model进行通信:相当于给子组件绑定props,同时也相当于绑定了自定义事件
父组件:(可以在传递多个参数)

<template>
  <div>
    <h1>v-model:{{pageNo}}{{pageSize}}</h1>
    <hr />
    <Child1 v-model:pageNo="pageNo" v-model:pageSize="pageSize"></Child1>
  </div>
</template>

子组件
<template>
  <div class="child2">
    <button @click="handler">pageNo{{ pageNo }}</button>
    <button @click="$emit('update:pageSize', pageSize + 4)">
      pageSize{{ pageSize }}
    </button>
  </div>
</template>
 
<script setup lang="ts">
let props = defineProps(["pageNo", "pageSize"]);
let $emit = defineEmits(["update:pageNo", "update:pageSize"]);
//第一个按钮的事件回调
const handler = () => {
  $emit("update:pageNo", props.pageNo + 3);
};
</script>
useAttrs: 如果和props同时使用的话props接受了的属性,useAttrs接受不到了就。
父组件
<template>
  <div>
    <h1>useAttrs</h1>
    <ButtonTitle type="primary" size="small" :icon="Edit" title="编辑按钮" ></ButtonTitle >
  </div>
</template>

子组件
<template>
  <div :title="title">
     <el-button :="$attrs"></el-button>   
  </div>
</template>
 
<script setup lang="ts">
import {useAttrs} from 'vue';
let $attrs = useAttrs();
let props =defineProps(['title']);
//但是props接受了useAttrs方法就获取不到了
console.log($attrs);
</script>

provide与inject 实现隔代之间的数据传递

//爷爷组件
<template>
  <div class="box">
    <h1>爷爷组件{{money}}</h1>
    <hr />
    <Child></Child>
  </div>
</template>
 
<script setup lang="ts">
import Child from "./Child.vue";
import { ref, provide } from "vue";
let money= ref("1000");
//祖先组件给后代组件提供数据
provide("MONEY", money);
</script>


 //孙子组件:(可以对接受到的数据进行修改)
 <template>
  <div class="child1">
    <h1>孙子组件</h1>
    <p>{{money}}</p>
    <button @click="updateMoney">更新数据</button>
  </div>
</template>
 
<script setup lang="ts">
import {inject} from 'vue';
//注入祖先组件提供数据
let money = inject('MONEY');
const updateMoney = ()=>{
   money.value  = '自行车';
}
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Vue3.0来了,你还学的动吗? 2020年9月底,Vue3.0正式版终于发布了。Vue在全球拥有 130 多万用户 ,它被应用于各种不同的场景中。而在国内,更是最火热的前端框架,2.0与3.0的开发模式有了很大的改变,所以3.0的全新版本势必会引发新的一波学习潮流。对于前端开发者来说,不管你嘴上如何“学不动”,注定离不开“真相定律”,Vue3.0是你提升自身技术能力,晋升中级工程师一定要掌握的。  本课程将基于 Vue3.0 正式版,从Vue基础语法入手,全面掌握 Vue3.0 全家桶技术栈,并结合实战项目开发,让你拥有Vue3.0项目开发经验,更好的掌握Vue开发企业项目的流程 。 本课程共包括三个模块 一、Vue基础篇 本模块将讲解Vue3.0基本用法、插值表达式、常用指令等知识点,还会精讲Vue 3.0核心语法,如计算属性、过滤器、监视器、模板、生命周期等内容。会带你深入理解Vue组件化技术,讲解全局组件和局部组件的定义,组件间数据传递,以及Vue内置组件等知识点。让你掌握模块化的概念,会通过Vue脚本架搭建项目,并掌握使用Axios发送AJAX请求,让你快速入门Vue3.0。 二、Vue核心篇 这个模块会带你讲解Vue3.0全家桶的知识点(Vue Router路由+Vuex状态管理),涉及Vue路由的用法、包括路由嵌套、路由模式、编程式导航、路由守卫等,还会全面讲解Vuex状态管理机制及使用,理解state、mutation、action等核心概念,让你轻松掌握Vue全家桶。 三、项目实战篇 实战项目会贴近企业流程,按照企业级别代码质量和工程开发流程进行授课,让你理解这套技术在企业中被使用的真实流程,更好的掌握Vue各个基础知识点。项目开发流程包括项目需求分析->环境搭建与配置->搭建远程Git仓库->接口分析->项目开发->打包上线。实战项目涉及内容
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值