React coder 转 Vue3 coder

在实验室用的react,实习用的vue,干我们这一行,框架再怎么变,基本思想和设计模式不怎么变,但是呢框架也是有区别的,之前学习哔哩哔哩尚硅谷的vue3,记不住就恼火了哇,所以这篇文章就相当于学习笔记了。

核心语法

组合式api

vue2的option(选项式)api 将数据、方法、计算属性分散在datamethodscompute中的,如果要增加或者修改一个需求,就需要分别修改datamethodscompute不利于维护和复用

选项式api

vue 提供了setup钩子函数,从而实现组合式api

选项式api是将数据、方法集中在一起,在我们增加一个数据和方法的时候直接增加,而不需要像组合式那样到处都要加一部分

原始setup

原始的setup我们直接在script里面 写入setup函数,里面的变量就是我们的数据,里面的方法也是供我们使用的方法,但是我们的数据和方法 需要return才能使用

注意: 这种写法没有用setup语法糖,我们仍然可以使用 data,method,compute等,但是 setup是优先执行于data,因此 data是可以访问到setup里面的数据,而setup不能访问到data里面的数据,同时setup不能使用this

js 复制代码
<script lang="ts">
export default {
  name: 'Person',
  data(){
    return {
      c:this.name,// data能访问setup里面的数据
      age:13,
    }
  },
  methods:{
  },
  setup(){//setup不能访问到data里面的数据
    let name = 'lisi'
    return {name}
  },
}
</script>

setup语法糖

setup语法糖需要我们将setup字段写到script标签里面,我们定义的数据和方法他自动帮我返回,我们不需要再写return

js 复制代码
<script lang="ts" setup>
let name = 'lisi'
</script>

响应式数据

reactive响应式数据

reactive用于声明响应式复杂数据类型,修改对象的元素,直接修改即可,但是要修改整个对象 则需要使用Object.assign,否则会失去响应式,

js 复制代码
<template>
  <div>{{ Person.name }}</div>
  <div>{{ Person.age }}</div>
  <button @click="changeName"></button>
</template>

<script lang="ts" setup>
import {ref, reactive} from 'vue'
let Person = reactive({name:'lis',age:18})
const changeName= ()=>{
  Person.name='王五'//直接修改
}
const changeAge= ()=>{
  Person.age+=1//直接修改
}
const changePerson = ()=>{
  Person= Object.assign(Person,{name:'wangwu',age:19})
}
</script>

我们打印Person显示的是一个Proxy代理对象,它也具有原始对象Object的方法.比如:代理的是一个Array 则也会有Array的一些方法和属性

注意: js提供了解构赋值,在reactive里面结构赋值时会失去响应式,要解构赋值的话使用toRefs()包裹一下即可,toRef的话 则是 let n = toRef(Person,"name")

ref响应式数据

在vue2中data里面的数据默认是响应式的,在vue3中可以接受vue2的写法。

vue3中,数据的响应式写法通过ref和reactive来声明的
注意 :首先声明这个ref并不是 <h2 ref="xxx">这个ref

js 复制代码
<script lang="ts" setup>
import {ref} from 'vue'
let name = ref('lisi')//通过ref声明的数据是响应式的
const changeName= ()=>{
  name.value='王五'//修改name 必须.value才能修改
}
</script>

同时ref也可以声明复杂数据类型

js 复制代码
<script lang="ts" setup>
import {ref} from 'vue'
let Person = ref({name:'lis',age:18})
const changeName= ()=>{
  Person.value.name='王五'//直接修改
}
const changeAge= ()=>{
  Person.value.age+=1//直接修改
}
const changePerson = ()=>{
  Person.value= Object.assign(Person.value,{name:'wangwu',age:19})
}
</script>

注意: 修改时要加上.value属性,同时ref声明的是复杂数据类型, 打印之后其实是proxy对象

computed计算属性

当计算属性所需要的元素变化时,他会自动计算出新的值,而且只会计算一次

js 复制代码
<template>
  <div>{{ firstName }}</div>
  <div>{{ lastName }}</div>
  <div>{{afterCompute}}</div>
  <div>{{afterCompute}}</div>
  <div>{{afterCompute}}</div>
  <button @click="changePerson">修改名字</button>
</template>

<script lang="ts" setup>
import {computed, ref} from 'vue'
let firstName =ref("王")
let lastName =ref("五")
const changePerson = () => {
  firstName.value="李"
}
let afterCompute = computed(()=>{
  return firstName.value+lastName.value
})
</script>

注意: 这样写computed属性是只读的,不能修改。比如上面的afterCompute我们不能在其他函数里面修改如果要修改的话,写成一个对象,并且有get和set方法

js 复制代码
<template>
  <div>{{ firstName }}</div>
  <div>{{ lastName }}</div>
  <div>{{afterCompute}}</div>
  <button @click="changePerson">修改名字</button>
  <button @click="changeAfterComputed">修改afterCompute</button>

</template>

<script lang="ts" setup>
import {computed, ref} from 'vue'
let firstName =ref("王")
let lastName =ref("五")
const changePerson = () => {
  firstName.value="李"
}
let afterCompute = computed({
  get(){
    return firstName.value+lastName.value
  },
  set(val){
    console.log(val)//最新值
    console.log(val.split(""))
    firstName.value=val.split("")[0]
    lastName.value=val.split("")[1]
  },
})
let changeAfterComputed = ()=>{
  afterCompute.value ="张三"
}
</script>

watch

watch的作用是监视数据的变化

监视ref基本数据类型

当ref数据变化时,watch会监听到,并且做出相应的变化,监视时 不需要写value

js 复制代码
let num =ref(0)
const addSum = () => {
  num.value+=1
}
const stopWatch = watch(num,(newValue,oldValue)=>{
  if(newValue>10){
    stopWatch()//停止监视
  }
  console.log('num+1了')
})
监视ref复杂数据类型

当我们监听的是复杂数据类型时,我们传入的参数是复杂数据Object,那么他监视的话,是看的地址变没变,如果想要监视内部属性变没变,则要开启深度监视deep

js 复制代码
<template>
  <div>{{ Person.name }}</div>
  <div>{{ Person.age }}</div>
  <button @click="changeAge">age+1</button>


</template>

<script lang="ts" setup>
import {computed, ref, watch} from 'vue'
let Person =ref({
  name:'张三',
  age:18
})
const changeAge = () => {
  Person.value.age+=1
}
const changeName = () => {
  Person.value.name+='~'
}
const stopWatch = watch(Person,(newValue,oldValue)=>{//监视Person地址变没变
        console.log('ly',newValue,oldValue)
})
const stopWatch = watch(Person,(newValue,oldValue)=>{
        console.log('ly',newValue,oldValue)
},{deep:true,immediate:true})//深度监视,监视的值,immediate表示第一次要监视,也就是旧的值为undefined
</script>
监视reactive的响应式数据

监视reactive的响应式数据,默认开启了深度监视,3.4版本之后可以关闭了

监视ref或者reactive定义的对象类型数据中的某个属性

如果该属性值 不是对象类型 ,需要写成getter函数 形式

如果该属性值 依旧是对象类型 可以写成函数形式,也可以直接编写,不过推荐写成getter函数形式

getter函数:能返回一个值的函数

js 复制代码
watch(()=>Person.name,(newValue,oldValue)=>{
 console.log('ly',newValue,oldValue)
})

监视多个数据

写成数组的形式

js 复制代码
watch([()=>Person.name,()=>Car.speed],(newValue,oldValue)=>{
 console.log('ly',newValue,oldValue)
})

watchEffect

watch要指定监视的值,不指定就不监视。而watchEffect则不需要指定监视的属性,直接写逻辑,就可以智能判断,同时在声明的时候 watchEffect会立即运行一个函数

js 复制代码
watchEffect(()=>{
  if(Person.value.age>20){ // 当age 大于20时 就会触发
    console.log(Person.value.age)
  }
})

Porps使用

vue3的Props 用defineProps definePropes里面的值是一个数组,值是父组件传过来的key

js 复制代码
<Person a="1+1" :b="1+1">
js 复制代码
let s = defineProps(['a','b'])
console.log(s)

生命周期

一般网络请求放在Mounted生命周期里面

自定义hooks

hooks说白了 就是将一个数据和对应修改数据的方法封装成一个hook,hooks本身是 js或者ts文件,命名基本上是useXXX.ts useSum.ts

js 复制代码
import {onMounted, ref} from "vue";

export default function () {
    //数据
    let num: number =ref(0)
    //方法
    function addNum() {
        console.log(num.value)
        num.value+=1
    }
    onMounted(() => {
        addNum()
    })

    // 向外部提供东西
    return {num,addNum}
}

Person.vue

js 复制代码
<template>
  <div>{{ num }}</div>
  <button @click="addNum">点击+1</button>
</template>

<script lang="ts" setup>
 import useSum from "@/components/useSum";
 const {num,addNum } =useSum()
</script>

路由

组件通信方式

props通信

在vue里面父子通信和react差不多,父传子直接props传递即可,子传父则需要父组件给子组件一个函数,子组件调用这个函数即可,并且将数据通过函数参数的形式传递即可

Father.js 复制代码
<template>
    <div class="Father">
      <h2>父组件</h2>
      <h4>来自子组件的信息:{{childMessage}}</h4>

      <Child :message="fatherMessage" :getChildMessage="getChildMessage"></Child>
    </div>
</template>

<script setup  lang="ts">
import Child from "./components/Child.vue";
import {ref} from "vue";
let fatherMessage=ref('来自父组件的数据')
let childMessage =ref('')
//传递一个函数,通过数据通过参数的形式获得
let getChildMessage = (data)=>{
  childMessage.value = data
}
</script>

<style scoped>
.Father{
  background-color: aqua;
}
</style>

自定义事件

自定义事件我们经常用到,说自定义事件之前,我们先说一下获得事件对象,vue是通过$event来获取

js 复制代码
<button @click="getEvent($event)" >获取事件对象</button>

let getEvent = (event) => {
  console.log(event.target)
}

切回正题,自定义事件 首先子组件先绑定一个haha事件,这个事件调用getData函数

js 复制代码
<Child @haha ='getData'></Child>

在子组件里面声明事件 通过defineEmits

js 复制代码
const emit = defineEmits(['haha'])

在通过点击的时候触发这个事件,当然 你可以在任何你想要的时候触发事件,这里用作点击比较好理解

js 复制代码
<button @click="emit('haha')" >点击触发自定义事件</button>

结果

v-model

v-modal其实本质做了两个事情,第一个是将数据进行渲染,比如原生的input框将数据进行渲染,第二个则是改变数据,就如下面第二个input框,触发input事件的时候将userName数据更改,从而达到双向绑定,这是在普通的组件上面,那么在自定义组件上面呢?和第二种写法一样的模拟即可

js 复制代码
<input type="text"  v-model="userName">
<input type="text" :value="userName" @input="userName = (<HTMLInputElement>$event.target).value">
Father.js 复制代码
<Child
    :modelValue = 'userName'
    @update:modelValue = "userName = $event">
</Child>
child.js 复制代码
<template>
  <input
      type="text"
      :value="modelValue"
      @input = "emit('update:modelValue',$event.target.value)"
  />
</template>

<script lang="ts" setup>
import {ref} from "vue";
//将数据拿过来
defineProps(['modelValue'])
//将数据更改
let emit = defineEmits(['update:modelValue'])
</script>
<style>
.child {
  background-color: bisque;
  margin-left: 50px;
}
</style>

这样我们就模拟了v-model,但是我们偷懒 可以直接用v-model,总之写这么多代码 就是了解一下v-model的本质是什么

js 复制代码
<Child v-model = 'userName'></Child>

插槽

插槽的作用在于,我们封装组件的时候,外部引用组件,同时在组件标签之间写代码,标签之间的内容不会显现 比如

App.vue 复制代码
<template>
  <Person a="1+1" :b="1+1">
    <div>你好</div>
  </Person>
</template>
Person.vue 复制代码
<template>
  <div>{{ num }}</div>
  <button @click="addNum">点击+1</button>
</template>

<script lang="ts" setup>
 import useSum from "@/components/useSum";
 const {num,addNum } =useSum()
</script>

我们在Person组件里面写入了【你好】但是组件内是没有插槽的,所以不会显现

默认插槽

Person.vue 复制代码
<template>
  <div>{{ num }}</div>
  <button @click="addNum">点击+1</button>
    <slot/>
</template>

<script lang="ts" setup>
 import useSum from "@/components/useSum";
 const {num,addNum } =useSum()
</script>

这样使用slot之后,div里面的内容就能显现

记名插槽

上面讲的默认插槽只有一个,那如果有多个插槽,顺序该怎么弄呢?这时候就要用到记名插槽了 下面代码纵使s2在上面,但是插槽内 s2写在s1下面,所以展现的时候 s1展现在上面

app.vue 复制代码
<template>
  <Person a="1+1" :b="1+1">
    <template #s2>
      <div >你好</div>
    </template>
    <template #s1>
      <div >我不好</div>
    </template>
  </Person>
</template>
Person.vue 复制代码
<template>
  <div>{{ num }}</div>
  <button @click="addNum">点击+1</button>
  <slot name="s1" />
  <slot name="s2" />

</template>

作用域插槽

上面的两种形式都是 父传给子数据,那假如子要传给父数据,那么我们只需要在 slot里面写入数据即可

app.vue 复制代码
<template>
  <Person a="1+1" :b="1+1">
  // params是个对象 里面的key有data 值是list
    <template v-slot = 'params'>
      <div >你好</div>
    </template>
  </Person>
</template>
Person.vue 复制代码
<template>
  <div>{{ num }}</div>
  <button @click="addNum">点击+1</button>
  <slot name="s1" :data='list' />
</template>

总结

换框架无所谓,但是基础细节还需要过一遍,当然学一门框架最好的方法就是去不断的实践。这篇文章就算自己的总结吧,方便回头来能快速开发

相关推荐
以对_7 分钟前
uview表单校验不生效问题
前端·uni-app
程序猿小D1 小时前
第二百六十七节 JPA教程 - JPA查询AND条件示例
java·开发语言·前端·数据库·windows·python·jpa
奔跑吧邓邓子2 小时前
npm包管理深度探索:从基础到进阶全面教程!
前端·npm·node.js
前端李易安2 小时前
ajax的原理,使用场景以及如何实现
前端·ajax·okhttp
汪子熙2 小时前
Angular 服务器端应用 ng-state tag 的作用介绍
前端·javascript·angular.js
杨荧2 小时前
【JAVA开源】基于Vue和SpringBoot的旅游管理系统
java·vue.js·spring boot·spring cloud·开源·旅游
Envyᥫᩣ3 小时前
《ASP.NET Web Forms 实现视频点赞功能的完整示例》
前端·asp.net·音视频·视频点赞
Мартин.6 小时前
[Meachines] [Easy] Sea WonderCMS-XSS-RCE+System Monitor 命令注入
前端·xss
一 乐8 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
昨天;明天。今天。8 小时前
案例-表白墙简单实现
前端·javascript·css