Vue3操作

Vue3

集成环境

使用官方脚手架来

  1. 使用webpack打包工具vue create 项目名

  2. 使用vite来打包

    npm init vite-app 项目名
    npm i
    cd 项目名
    npm run dev
    

    优势:

    • 开发环境中,无需打包操作,可以快速冷启动
    • 轻量快速的热重载
    • 按需编译,不用等待整个引用都加载完成

setup

是vue3的一个新的配置项,值是一个钩子函数

用法

  • 直接写配置项setup()

    export default {
      setup() {
    }
    }
    

  • 语法糖的写法setup写script标签上

    <script setup>
    </script>
    

返回值

  • 返回一个对象,对象中的方法,属性在模板中可以直接使用
  • 返回一个渲染函数,可以自定义渲染函数,这时候,模板中内容的会失效

注意

  • 尽量不要和vue2混合使用
    • vue2配置中可以访问到setup中的属性和方法,但setup中不能访问到vue2中的配置
    • 如果有重名冲突,setup优先
  • 在setup中不能使用this
  • setup不能是一个asyn函数,因为返回的不再是return的对象,而是primise,模板看不到return对象中的属性(后期可以返回一个promise,但要配合suspense和异步组件一起使用)

ref函数

isRef

作用:判断是否是一个Ref对象,返回值是一个布尔值

let price = toRef(person.zhiye,'price')
console.log(isRef(price))

toRef

作用:创建一个ref对象,其value值指向另一个对象的指定属性

let name = toRef(preson,'name')

适用场景:某一个对象的某个属性单独使用,又想要又响应式功能

import {reactive, toRef, toRefs} from 'vue'
let person = reactive({
    name: '张三',
    id: 1,
    age: 34,
    zhiye: {
        price: 4432,
        title:'前端工程师'
    }
})

// 用法:传入参数,第一个参数是对象,第二参数是要处理的响应式数据的值(字符串)

let price = toRef(person.zhiye,'price')
let changeprice = () => {
    price.value = 10000
    // console.log()

}

注意:toRef包裹的对象如果想要修改,用price.value的方式修改

拓展:toRefs功能和toRef类似,不同的是toRefs可以指定多个ref对象(一层)

let {a,b}=toRefs(obj)
// let a = toRef(obj.a) let b = toRef(obj.b) 隐式代码
  • toRefs函数接收一个响应式对象作为参数

reactive函数

计算属性

监听属性

watch

监听属性和vue2的用法相似

  • 对于监视reactive定义的响应式数据时,oldvalue无法正确获取,强制开始了深度监视(deep的配置失效)
  • 监视reactive定义的响应式数据的某一个值时:deep配置有效
<script setup>
import { ref,watch } from 'vue'

let studentId = ref(32)
let studentname = ref('lisi')

watch(studentId,(date)=> {
    console.log('改变学生信息')
})
let chang = ()=> {
    studentId.value = 33
    studentname.value = 'wangwu'

}

</script>
<template>
    <div class="student">
        <h2>学生学号:{{studentId}} <br> 学生姓名:{{studentname}}</h2>
        <button @click="chang">改变学生id号码</button>
    </div>
</template>

watchEffect

是一个函数,不用指定某一个属性,监听回调里面用了哪个属性就调用监听哪个属性

和compputed类似,区别

  • computed必须要写返回值,更注重的是结果,watchEffect注重的是过程
//setup
import {watchEffect} from 'vue'
watchEffect(()=> {
  let x1 = sum.value
  console.log('调用了watchEffect')
})

其他API

shallowReactive与shallowRef

  • shallowReactive:只处理对象外层属性的响应式(浅响应式)
  • shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理

readonly与shallowReadonly

  • readonly:让一个响应式数据变为只读(深可读)
  • shallowReadonly:让一个响应式变为只读的(浅只读)

toRow和markRow

  • toRow
    • 作用:将响应式数据生成普通对象
  • markRow
    • 作用:标记一个对象,使其永远不会成为响应式
    • 应用场景:有些不应该被设置为响应式的,例如复杂的第三方库
    • 当渲染的具有不可变的数据源的大列表,跳过响应式可以提高性能

Vue3生命周期

和Vue2类似,但有一些改变

  • 将beforeDestory改名为beforeUnmount,destoryed改名为unmounted
  • 新增了一个setup生命周期函数,在setup中不能使用this,所以它是在beforecreated之前
onBeforeMount onMounted
onBeforeUpdate onUpdated
onBeforeUnmount onUnmounted
onErrorCaptured
onRenderTracked
onRenderTriggered

内置组件

Fragment

  • 在vue2中,必须有一个根标签,但在vue3中,可以不写跟标签,内部会将标签包含在Fragment虚拟元素内

优点:减少层级的嵌套,减少内存占用

Teleport

可以将模板移动到组件外的地方

teleport组件,用to属性来指定位置

<template>
  <div class="appbig">
    <teleport to="body">
      <div class="poping">
        <button>teleport点击弹窗</button>
      </div>
    </teleport>
  </div>
</template>

注意

  • 修改的时候用flag.value来修改,但是模板中使用直接写flag

Suspense

本身底层是用具名插槽实现的,分别名为defaultfallback,在异步加载组件的时候,如果组件没有加载出来,会先有一个默认模板(模板内容可以是一个组件)

  1. 引入异步组件

    import {defineAsynComponent} from 'vue'
    const Child = defineAsynComponent(()=> import('./Child.vue'))
    
  2. 使用Suspense包裹组件,配置defaultfallback

<Suspense>
  <template v-slot:default></template>
  <template v-slot:fallback></template>
</Suspense>

组件间通信

privide和inject

实现祖孙组件间的通信

  1. 父组件又provide选项来提供数据

    import {provide} from 'vue'
    setup() {
      ...
      privide('car',car)
    }
    

  2. 子组件用inject项目来使用这些数据

    import {inject} from 'vue'
    setup() {
      ...
      let car = inject('car')
    }
    

属性传值

  1. 父组件用:绑定属性

  2. 子组件要引入defineProps,用来接收传来的数据

    import { defineProps } from 'vue';
    let obj = defineProps(['title'])
    

    在模板中用{{obj.title}}

自定义事件

  1. 引入defineEmits

  2. 调用

    let emit = defineEmits()
    emit('myclick')
    

在哪里定义的自定义事件,就在哪里写自定义调用的函数

// 父组件 app.vue
<script setup>
import Zidingyi from "./components/zidingyi.vue";
// import Poping from './components/Poping.vue';
let fn = ()=> {
  alert('what 5')
}
</script>

<template>
  <div class="appbig">
    <!-- <Poping msg="msg数据"></Poping> -->
    <Zidingyi @myclick="fn"></Zidingyi>
  </div>
</template>


//子组件
<script setup>
import { ref,defineEmits } from 'vue'
let num = ref(0)
let emit = defineEmits()
let add = ()=> {
    num.value++
    if(num.value==5) {
        emit('myclick')
        console.log('触发')
    }
}

</script>
<template>
    <div class="zdy">自定义事件
        <h2>{{num}}</h2>
        <button @click="add">加一</button>
    </div>
</template>

公共配置

实例API(app) 全局配置(vue)
Vue.config.xxx app.config.xxxxx
Vue.config.productionTip 移除
Vue.component app.component //定义全局组件
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use
Vue.prototype app.config.globalProperties //原型链中的东西,放在此配置中,具体使用如下
  1. 设置app.config.globalProperties.$axios='axios'

  2. 组件中使用

    import {getCurrentInstance} from 'vue'
    let vc = getCurrentInstance()
    console.log(vc.proxy.$axios)
    

注意:getCurrentInstance只能在组件中的钩子函数中获取实例

网络配置

import axios from 'axios'
axios.defaults.baseURL="http://127.0.0.1:8080/api"
app.config.globalProperties.$axios = axios

配置代理

//vite环境:
proxy: {
'/api': {
target: 'http://127.0.0.1:7001', // 代理的目标地址
rewrite: (path) => path.replace(/^\/api/, '/'), // 路径重写
changeOrigin:true,
// secure: true, // target是否https接口
// ws: true, // target是否代理websockets
}
}

路由配置

下载npm i vue-router

配置路由在router/index.js中,和vue2中类似

main.js中导入挂载

import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index.js'
const app = createApp(App)
app.use(router)
app.mount('#app')

数据仓库

vue3中有vuex也有Pinia

这里我们主要学习Pinia

  1. 下载npm i pinia

  2. 在main.js中导入

    import {createPinia}from 'pinia'
    //创建实例并use到app中
    app.use(createPinia())
    
  3. 创建仓库

    //store/car.js
    import { defineStore } from "pinia";
    export const useCar = defineStore('car',{
      state: ()=> {
        return {
          carname: '大众汽车'
        }
      }
    }
                                     )
    

    defineStore(storeid,option):提供给es6使用this

    • storeid:字符串的仓库唯一标识

    • option:state返回的对象为我们要使用的数据

      • state

      • getters:可以当作计算属性使用,当函数用到的属性使用的时候,就会更新

        //router/index.js
        defineStore('car',{
          state: ()=> {
            return: {}
          },
          getters: {
            age: (state)=> {}
          }
        })
        

      • action:可以异步操作,this可以使用,this为仓库上下文对象

        //router/index.js
        defineStore('car',{
          state: ()=> {
            return: {}
          },
          getters: {
            age: (state)=> {}
          },
          actions: {
            tool(){
              console.log(this)
            }
          }
        })
        

      getters和action区别

      • action可以异步操作
      • 统一修改
  4. 看具体创建仓库的方式,在组件中导出仓库并时候

    //setup
    import {useCar} from '../store/Car.js'
    let carInfo = useCar()
    console.log(carInfo.carname)
    
    // 结构赋值的方式
    let {carname} = carInfo
    
  5. 修改仓库,直接修改(vuex不同)

    //setup
    import {useCar} from '../store/Car.js'
    let carInfo = useCar()
    carInfo.carname = '修改为特斯拉汽车'
    

    注意:利用结构赋值的carname修改的数据,不具备响应式的功能

    解决方法,可以使用toRefs

    //setup
    import {toRefs} from 'vue'
    let {carname} = toRefs(carInfo)
    

    批量修改

    • carInfo.$patch:修改数据
    //setup
    carInfo.$patch({
      carname: '修改为特斯拉汽车',
      a: '90' //修改的a,原本的仓库不存在
    })
    
    • 批量修改的状态刷新一次
    • 如果数据不存在,比如上方例子的a,vue3中不会添加a值到仓库中。注意:其他的框架,比如react是会添加的
  6. 订阅修改:通过patch修改状态时就会触发一次

    carInfo.$subscribe((n1,carInfo.carname)=> {
      //pass
    })
    
  7. 仓库可以使用其他的仓库

    //car 仓库使用userinfo仓库跟组件使用方式
    import {userinfo} from '../store/userinfo'
    let store = userinfo()
    

posted @ 2022-10-08 15:02  a立方  阅读(41)  评论(0编辑  收藏  举报