Vue3 极速入门🚀②

385 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情 image.png 技术更新很快,时代在推你进步,你却停滞不前,只会被时代淘汰。迫于内卷压力,再不学 vue3 真的感觉在跟时代划一道鸿沟。接下来让我们以最快的脚步认识vue3

上一篇第一至第八点【传送门

十. toRaw / markRaw

toRaw

返回 reactive 或 readonly 代理的原始对象。这是一个“逃生舱”,可用于临时读取数据而无需承担代理访问/跟踪的开销,也可用于写入数据而避免触发更改。建议保留对原始对象的持久引用。请谨慎使用。

const foo = {};
const reactiveFoo = reactive(foo);
console.log(toRaw(reactiveFoo) === foo) // true
<script>
import { reactive, toRaw, isReactive } from 'vue'
export default {
  name: 'HomeView',
  setup () {
    const person = reactive({
      name: '小明',
      age: 18,
      likeFood: {
        fruits: {
          apple: '草莓'
        }
      }
    });
    const person2 = toRaw(person);
    console.log(person)
    console.log(person2)

    console.log(isReactive(person))
    console.log(isReactive(person2))
    return {

    }
  },
}
</script>

image.png

markRaw

标记一个对象,使其永远不会转换为 proxy。返回对象本身。

<script>
import { reactive, markRaw, isReactive } from 'vue'
export default {
  name: 'HomeView',
  setup () {
    let person = {
      name: "小明",
      age: 18
    };
    const markRawObj = markRaw(person); //标记person
    const reactiveObj = reactive(markRawObj); //尝试转为响应式
    console.log(isReactive(reactiveObj)) // false,说明未转成响应式
    console.log(reactiveObj)

    const obj = reactive({
      name: "小风",
      age: 19
    })
    console.log(obj)
    return {};
  }
}
</script>

image.png

十一. computed 计算属性

接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref 对象。

<template>
  <div>姓名:{{ name }}</div>
  <div>年龄:{{ age }}</div>
  <div>合并信息:{{ getInfo }}</div>
</template>

<script>
import { ref, computed } from "vue";
export default {
  name: 'HomeView',
  setup () {
    let name = ref('小明')
    let age = ref(21)

    //计算属性
    let getInfo = computed(() => {
      return `${name.value}${age.value}`
    })
    getInfo.value += "尝试新增点东西"; //不允许修改,这里是非法的,修改不成功的
    return {
      name,
      age,
      getInfo,
    }
  }
}
</script>

image.png

或者,接受一个具有 get 和 set 函数的对象,用来创建可写的 ref 对象。

const count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: val => {
    count.value = val - 1
  }
})

plusOne.value = 1
console.log(count.value) // 0

十二. watch 监听

watch用法与vue2.x的差不多,watch(data,handler,object)。

  • data:可以是返回值的getter函数,也可以是 ref。
  • hander: 回调函数
  • object: 可选配置项{ immediate : true, deep : true } //立即执行和深度监测
<template>
  <ul>
    <li
      v-for="(item, index) in courseList"
      :key="index"
      @click="selectCourseFun(index)"
    >
      {{ item }}
    </li>
  </ul>
  <div>默认课程:{{ defaultCourse }}</div>
  <div>选中的课程:{{ selectCourse }}</div>
</template>

<script>
import { ref, reactive, toRefs, watch } from "vue";
export default {
  name: 'HomeView',
  setup () {
    const defaultCourse = ref("javaScript进阶");
    const data = reactive({
      courseList: ["vue3初识", "Node.js进阶", "css世界"],
      selectCourse: "",
      selectCourseFun: (index) => {
        data.selectCourse = data.courseList[index];
        defaultCourse.value = data.courseList[index];
      }
    })
    //监听单个
    // watch(defaultCourse, (newValue, oldValue) => {
    //   console.log(`new--->${newValue}`);
    //   console.log(`old--->${oldValue}`);
    // })
    
    //监听多个
    watch([defaultCourse, () => data.selectCourse], (newValue, oldValue) => {
      console.log(`new--->${newValue}`);
      console.log(`old--->${oldValue}`);
    })
    return {
      defaultCourse,
      ...toRefs(data)
    }
  }
}
</script>

GIF7.gif

十三. watchEffect

立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。

  • 不需要手动传入依赖
  • 每次初始化时会执行一次回调函数来自动获取依赖
  • 无法获取到原值,只能得到变化后的值
<template>
  <input type="text" v-model="name" />
</template>

<script>
import { reactive, toRefs, watchEffect } from "vue";
export default {
  name: 'HomeView',
  setup () {
    let data = reactive({
      name: "小明",
      sex: "男",
    });
    watchEffect(() => {
      console.log(data.name); //需要监听哪个就写哪个
    });
    return {
      ...toRefs(data),
    };
  }
}
</script>

GIF2.gif

十四. 注意事项

Vue.prototype 替换为 config.globalProperties

//vue2.x
//main.js
Vue.prototype.$test = "测试" 

//页面xx.vue
let value = this.$test;
//vu3.x
//main.js
const app = createApp({}); 
app.config.globalProperties.$test = "测试"

//页面使用 
<template> 
   <h1>{{ $test }}</h1> //直接使用 
</template> 
import {  getCurrentInstance } from "vue"; 
export default { 
   setup(){ 
     const { appContext } = getCurrentInstance(); 
     console.log(appContext.config.globalProperties.$test)  //可以通过这样获取 
     } 
  }

废弃 v-bind:title.sync 写法

//父组件
<ChildComponent :title.sync="pageTitle" />  //vue2.x写法
<ChildComponent v-model:title="pageTitle" /> //vue3.x写法

//子组件
<template>
  <h1>{{ title }}</h1>
  <button @click="changeTitle('newTitle')">Change</button>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
  props: {
    title: String
  },
  setup () {
    function changeTitle (val) {
      this.$emit("update:title", val)
    }
    return {
      changeTitle
    }
  }
})
</script>

废弃 filter 过滤器

在 3.x 中,过滤器已移除,且不再支持。取而代之的是,我们建议用方法调用或计算属性来替换它们。

//父页组件
<template>
  <child v-model:name="name" v-model:value="value"></child>
</template>
<script>
import { defineComponent, reactive, toRefs } from 'vue'
import child from "@/components/child";
export default defineComponent({
  components: {
    child
  },
  setup () {
    let params = reactive({
      name: "测试过滤功能",
      value: 12.0124525721
    })
    return {
      ...toRefs(params)
    }
  }
})
</script>
//子组件
<template>
  <h1>{{ name }}</h1>
  <h2>{{ newValue }}</h2>
</template>
<script>
import { defineComponent, computed } from "vue";
export default defineComponent({
  props: {
    name: String,
    value: Number,
  },
  setup (props) {
    let newValue = computed(() => {
      return Number(props.value.toFixed(2))
    })
    return {
      newValue
    }
  }
})
</script>

使用全局方法实现过滤器

//main.js
const app = createApp(App);
app.config.globalProperties.$filters = { 
    exactTwoDecimal(val){ 
        return Number(val.toFixed(2)) 
    }
}

//页面
<template> 
   <h2>{{ $filters.exactTwoDecimal(value)}}</h2> 
</template>