埃隆马斯克-科技资讯-JinNianX

点击以下链接进入:
https://www.elonmusk.cn/

Vue3_06_CompositionApi | 瑾年-JinNianX-瑾年的学习记录-科技漫步

Vue3_06_CompositionApi


Composition API

以后开发不再用options api 而是composition api,这个api其实就是setup函数

compositionAPI:组合API

optionsAPI:选项API

options和composition对比

1252

1253

1-如上optionsAPI实际上就是在操控data中的数据,但是对它的操作遍布于各种api中,如methods,computed,watch等等。 弊端就是太分散了不利于分析代码等。

2-compositionAPI就是把对同个内容的操作全部写到一个函数内,然后这个函数还可以被很简单的抽取出进行复用。

认识compositionApi

1254

1255

1256

<template>
<!-- template中ref对象自动解包 -->
 <h2>数字:{{ counter }}</h2>
 <button @click="add">+1</button>
 <button @click="sub">-1</button>
</template>


<script>
import {ref} from "vue"
//import {reactive} from "vue"
//import {reactive,ref} from "vue" 这种写法同时导入也可以
  export default {
    setup(){
//注意此时counter其实就是一个ref对象了,而不是简单的100,所以想使用这个100,必须通过counter.value
      let counter = ref(100)
      // function add(){}
      const add =()=>{
        counter.value +=1
      
      }
      // function sub(){}
      const sub =()=>{
        counter.value -=1
      }
      return{
        counter,
        add,
        sub
      }
    }
  }
</script>


<style scoped>

</style>

步骤:

1-在script标签内书写setup函数

2-在setup函数中声明变量和使用箭头函数(普通函数也可以)声明会发生的事件

3-setup中所有声明的东西,必须return返回出去才可以使用

4-我们点击按钮发现没反应,其实普通数据counter已经变化了,但是它不是响应式数据不会被劫持代理,不会在页面上实时改变

5.1-导入vue提供的ref方法,使用ref包裹住数据,即可实现响应式。

5.1.1使用ref后,在script中必须通过counter.value才能取到真正的值,在template中的插值语法中不需要,因为有vue内部会自动解包。(解包就是自动取出其对象的value属性)

//注意此时counter其实就是一个ref对象了,而不是简单的100,所以想使用这个100,必须通过counter.value

5.2通过reactive函数

1257

react就是回应,反应的意思,reactive就是响应式,因为我们在setup中写的数据是普通数据,不会像在optionsAPI的data中的数据那样被vue劫持,所以是不会在页面中自动响应更新的。

需要我们手动通过reactive劫持(其实data响应式原理的底层也是通过reactive函数),注意:reactive函数必须传入复杂类型的参数,如上的传入对象,而不是是简单的字符串或者一个数字值。

什么时候用ref,什么时候用reactive

这里是coderwhy老师总结出的经验,我以后也就这样写,其实只要你需要响应式数据,ref和reactive都可以完成,但是各有各的优点。

<template>
  <div>
    <form>
      账号: <input type="text" v-model="account.username">
      密码: <input type="password" v-model="account.password">
    </form>
    
    <form>
      账号: <input type="text" v-model="username">
      密码: <input type="password" v-model="password">
    </form>

    <hr>

    <show-info :name="name" :age="age"></show-info>
  </div>
</template>

<script>
  import { onMounted, reactive, ref } from 'vue'
  import ShowInfo from './ShowInfo.vue'

  export default {
    components: {
      ShowInfo
    },
    data() {
      return {
        message: "Hello World"
      }
    },
    setup() {
      // 定义响应式数据: reactive/ref
      // 强调: ref也可以定义复杂的数据
      const info = ref({})
      console.log(info.value)

      // 1.reactive的应用场景
      // 1.1.条件一: reactive应用于本地的数据
      // 1.2.条件二: 多个数据之间是有关系/联系(聚合的数据, 组织在一起会有特定的作用)
      const account = reactive({
        username: "coderwhy",
        password: "1234567"
      })

      const username = ref("coderwhy")
      const password = ref("123456")

      // 2.ref的应用场景: 其他的场景基本都用ref(computed)
      // 2.1.定义本地的一些简单数据
      const message = ref("Hello World")
      const counter = ref(0)
      const name = ref("why")
      const age = ref(18)

      // 2.定义从网络中获取的数据也是使用ref
      // const musics = reactive([])
      const musics = ref([])
      onMounted(() => {
        const serverMusics = ["海阔天空", "小苹果", "野狼"]
        musics.value = serverMusics
      })


      return {
        account,
        username,
        password,
        name,
        age
      }
    }
  }
</script>

<style scoped>
</style>

来自本地的,有关联的数据就用reactive,为什么呢?

因为有关联的数据,比如账号密码,你使用reactive的方法就直接account.username和account.password即可,更方便使用。

其他场景一般都用ref函数

比如来自服务器的数据,使用ref的话,如上代码直接music.value=serverMusics即可,如果是使用reactive函数,那么你没法去把服务器的数据搞进去,或者说需要一个一个遍历进去,很麻烦。

hooks文件夹是什么?

https://blog.csdn.net/JaneLittle/article/details/127127644

vue3 借鉴 react hooks 开发出了 Composition API ,所以也就意味着 Composition API 也能进行自定义封装 hooks

vue3 中的 hooks 就是函数的一种写法,就是将文件的一些单独功能的js代码进行抽离出来,放到单独的js文件中,或者说是一些可以复用的公共方法/功能。其实 hooksvue2 中的 mixin 有点类似,但是相对 mixins 而言, hooks 更清楚复用功能代码的来源, 更清晰易懂。

安装Vue-devtool

作用:方便调试

1-直接在chorm商店下载(某些原因正常情况下打不开)

安装后如果不生效,重启下浏览器

2-找个安装教程手动安装,去github下载源码然后打包,拖到chorm拓展内。

1258

1259

认识readonly只读函数(了解)

1260

它的原理就是劫持了对象的set方法,让它无法被修改。

问题:子组件可以修改来自父组件通过父子通信,传递过来的数据,即修改props内的数据(如对象)。

规范准则:虽然这是可行的,但是不符合单项数据流的准则,如父组件将此数据传递给了3个子组件,然后其中一个子组件修改了数据,那么父组件根本不知道是谁改的,非常不利于维护。 这个准则在react内也要遵守

实在要修改这个数据呢?

在子组件内通过emit发送自定义事件给父组件,由父组件进行修改。

问题:当其他人在编写子组件的时候,他不知道这个单向数据流的准则,修改了数据应该怎么避免呢?

解决:在父组件内使用readonly函数包裹住需要传出到子组件的数据即可。那么这个数据将不能被修改。

app.vue
<template>
  <h2>App: {{ info }}</h2>
  <show-info :info="info" 
             :roInfo="roInfo" 
             @changeInfoName="changeInfoName"
             @changeRoInfoName="changeRoInfoName">
  </show-info>
</template>

<script>
  import { reactive, readonly } from 'vue'
  import ShowInfo from './ShowInfo.vue'

  export default {
    components: {
      ShowInfo
    },
    setup() {
      // 本地定义多个数据, 都需要传递给子组件
      // name/age/height
      const info = reactive({
        name: "why",
        age: 18,
        height: 1.88
      })

      function changeInfoName(payload) {
        info.name = payload
      }

      // 使用readOnly包裹info
      const roInfo = readonly(info)
      function changeRoInfoName(payload) {
        info.name = payload
      }

      return {
        info,
        changeInfoName,
        roInfo,
        changeRoInfoName
      }
    }
  }
</script>

<style scoped>
</style>

showinfo.vue
<template>
  <div>
    <h2>ShowInfo: {{ info }}</h2>
    <!-- 代码没有错误, 但是违背规范(单项数据流) -->
    <button @click="info.name = 'kobe'">ShowInfo按钮</button>
    <!-- 正确的做法: 符合单项数据流-->
    <button @click="showInfobtnClick">ShowInfo按钮</button>
    <hr>
    <!-- 使用readonly的数据 -->
    <h2>ShowInfo: {{ roInfo }}</h2>
    <!-- 代码就会无效(报警告) -->
    <!-- <button @click="roInfo.name = 'james'">ShowInfo按钮</button> -->
    <!-- 正确的做法 -->
    <button @click="roInfoBtnClick">roInfo按钮</button>
  </div>
</template>

<script>
  export default {
    props: {
      // reactive数据
      info: {
        type: Object,
        default: () => ({})
      },
      // readonly数据
      roInfo: {
        type: Object,
        default: () => ({})
      }
    },
    emits: ["changeInfoName", "changeRoInfoName"],
    setup(props, context) {
      function showInfobtnClick() {
        context.emit("changeInfoName", "kobe")
      }

      function roInfoBtnClick() {
        context.emit("changeRoInfoName", "james")
      }

      return {
        showInfobtnClick,
        roInfoBtnClick
      }
    }
  }
</script>

<style scoped>
</style>

当readonly后,就算是父组件本身也无法修改如上代码的roInfo,但是是可以通过原始info修改的。

1261

方法补充(了解)

1262

什么叫shallow呢,就是浅层,shallowReactive就是浅层响应,如上图代码,当firend内的name属性变化,那么浅层响应就不会被修改。

toRefs函数

作用:如下当我们使用reactive函数后,在template中每次都需要通过info.name,info.age等等来取值,有的人想直接写name和age怎么办呢?

答:我们可以将此对象解构

出现问题:解构后,数据会变成普通数据,没有响应式的功能

解决:使用toRef函数再进行解构。

<template>
  <div>
    <h2>info: {{ name }} - {{ age }} - {{ height }}</h2>
    <button @click="age++">修改age</button>
    <button @click="height = 1.89">修改height</button>
  </div>
</template>

<script>
  import { reactive, toRefs, toRef } from 'vue'
  
  export default {
    setup() {

        const info = reactive({
          name: "why",
          age: 18,
          height: 1.88
        })

        // reactive被解构后会变成普通的值, 失去响应式
        //多个解构
        const { name, age } = toRefs(info)
        //单个解构
        const height = toRef(info, "height")

        return {
          name,
          age,
          height
        }

    }
  }

</script>

<style scoped>
</style>

1263

为什么setup函数内无法使用this?

1265

1266

所以并不是原先官方文档说的setup之前,data和computed等没有被做解析,而是:

它内部源码,没有给setup绑定this,原先的optionsApi的methods,computed什么的都通过appy和bind等绑定了this。

问题:没有this,那我如何this.$emit呢?

setup(props,context)里有两个默认参数,第一个就是父组件传递进来的数据,第二个就包含了:

1267

setup中的对应原optionsApi的功能函数的使用

computed函数使用

1268

<template>
  <h2>{{ fullname }}</h2>
  <button @click="setFullname">设置fullname</button>
  <h2>{{ scoreLevel }}</h2>
</template>

<script>
import { reactive, computed, ref } from 'vue'

  export default {
    setup() {
      // 1.定义数据
      const names = reactive({
        firstName: "kobe",
        lastName: "bryant"
      })

      // const fullname = computed(() => {
      //   return names.firstName + " " + names.lastName
      // })
      const fullname = computed({
        set: function(newValue) {
          const tempNames = newValue.split(" ")
          names.firstName = tempNames[0]
          names.lastName = tempNames[1]
        },
        get: function() {
          return names.firstName + " " + names.lastName
        }
      })

      console.log(fullname)

      function setFullname() {
        fullname.value = "coder why"
        console.log(names)
      }


      // 2.定义score
      const score = ref(89)
      const scoreLevel = computed(() => {
        return score.value >= 60 ? "及格": "不及格"
      })

      return {
        names,
        fullname,
        setFullname,
        scoreLevel
      }
    }
  }
</script>

<style scoped>
</style>

// const fullname = computed(() => {
   //   return names.firstName + " " + names.lastName
   // })

如上即computed在setup中的基本使用,其中默认只设置了get,没有set,如果要设置set如下

const fullname = computed({
      set: function(newValue) {
        const tempNames = newValue.split(" ")
        names.firstName = tempNames[0]
        names.lastName = tempNames[1]
      },
      get: function() {
        return names.firstName + " " + names.lastNamejs
      }
    })

其中computed()返回的也是一个ref对象,我们给fullname赋值,需要通过fullname.value

ref获取元素dom的使用

原先学了ref在optionsapi中是通过给标签设置ref属性,如

<div class="app">
   <h2 ref="title" class="title" :style="{ color: titleColor }">{{ message }}</h2>
   <button ref="btn" @click="changeTitle">修改title</button>

   <banner ref="banner"/>
 </div>

然后所有的拥有ref属性的标签的dom会存在与this.$ref这个对象中,如

console.log(this.$refs.title)
console.log(this.$refs.btn)

那么在setup 函数中无法使用this,应该怎么办呢?

app.vue
<template>
  <!-- 1.获取元素 -->
  <h2 ref="titleRef">我是标题</h2>
  <button ref="btnRef">按钮</button>

  <!-- 2.获取组件实例 -->
  <show-info ref="showInfoRef"></show-info>

  <button @click="getElements">获取元素</button>
</template>

<script>
  import { ref, onMounted } from 'vue'
  import ShowInfo from './ShowInfo.vue'

  export default {
    components: {
      ShowInfo
    },
    setup() {
      const titleRef = ref()
      const btnRef = ref()
      const showInfoRef = ref()

      // mounted的生命周期函数
      onMounted(() => {
        console.log(titleRef.value)
        console.log(btnRef.value)
        console.log(showInfoRef.value)

        showInfoRef.value.showInfoFoo()
      })

      function getElements() {
        console.log(titleRef.value)
      }

      return {
        titleRef,
        btnRef,
        showInfoRef,
        getElements
      }
    }
  }
</script>

<style scoped>
</style>

我们可以引入一个ref函数(compositionapi就是函数编程,那么optionsapi都会变成函数)

const titleRef = ref()
    const btnRef = ref()
    const showInfoRef = ref()

然后使用这个函数,主要变量名需要和需要获取dom的标签中ref属性的值相同(我刚学也不知道原理,只学怎么用)

然而我们发现直接获取

console.log(titleRef.value)
console.log(btnRef.value)
console.log(showInfoRef.value)

是获取不到的,因为在setup()执行的过程中,dom可能还没有被完全加载,所以需要加上onMounted已挂载的钩子函数

注意:在optionsapi中是mounted(),在setup中是onMounted()

onMounted(() => {
       console.log(titleRef.value)
       console.log(btnRef.value)
       console.log(showInfoRef.value)

       showInfoRef.value.showInfoFoo()
     })

如何获取组件的实例?

showinfo.vue
<template>
  <div>ShowInfo</div>
</template>

<script>
  export default {
    // methods: {
    //   showInfoFoo() {
    //     console.log("showInfo foo function")
    //   }
    // }
    setup() {
      function showInfoFoo() {
        console.log("showInfo foo function")
      }

      return {
        showInfoFoo
      }
    }
  }
</script>

<style scoped>
</style>

一样的,加ref属性即可,然后再使用ref()函数声明

<!-- 2.获取组件实例 -->
<show-info ref="showInfoRef"></show-info>
const showInfoRef = ref()

而且我们拿到组件的实例,也就是showInfoRef后,还可以在app.vue中通过这个实例调用shpwinfo.vue组件内的方法,如

showInfoRef.value.showInfoFoo()

组件的生命周期函数

Provide/Inject使用

watch/watchEffect

自定义Hook联系

script setup 语法糖

vue3.2版本才有


文章作者: 瑾年
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 周东奇 !
免责声明: 本站所发布的一切内容,包括但不限于IT技术资源,网络攻防教程及相应程序等文章仅限用于学习和研究目的:不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。本站部分信息与工具来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如有侵权请邮件(jinnian770@gmail.com)与我们联系处理。
  目录