Vue3简单历险记

133 阅读1分钟

!!!!!注意 示例很多

较于Vue2的比较

  • 更好的逻辑复用 与 代码组织 (composition组合式api)
  1. Vue3采用组合式Api(Composition API,代码组织更方便了,利于维护)。
  2. 官方对组合式Api的解释:通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与 <script setup> 搭配使用。这个 setup attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。比如,<script setup> 中的导入和顶层变量/函数都能够在模板中直接使用。
<script setup>
import { ref, onMounted } from 'vue'

// 响应式状态
const count = ref(0)

// 用来修改状态、触发更新的函数
function increment() {
  count.value++
}

// 生命周期钩子
onMounted(() => {
  console.log(`The initial count is ${count.value}.`)
})
</script>

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>
  • 更好的类型推导 (typescript支持),ts大名鼎鼎,就不需要过多介绍了。

Vue3新特性

  • 数据响应式与Vue2不同,采用proxy代理进行数据劫持,解决了: 例如数组的更新检测等bug, 大大优化了响应式监听的性能(原来检测对象属性的变化, 需要一个个对属性递归监听) proxy 可以直接对整个对象劫持
  • 虚拟DOM - 新算法 (更快 更小)
  • 提供了composition api, 可以更好的逻辑复用
  • 模板可以有多个根元素
  • 源码用 typescript 重写, 有更好的类型推导 (类型检测更为严格, 更稳定)

Vite相关知识(官方解读)

Vite(法语意为 "快速的",发音 /vit/,发音同 "veet")是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:

Vite 意在提供开箱即用的配置,同时它的 插件 API 和 JavaScript API 带来了高度的可扩展性,并有完整的类型支持。

个人理解:vite是一个与脚手架vue-cli类似的工具,其为鱿鱼团队开发的,开发距今日期较短,在package.json配置里面进行的配置是

  "scripts": {
    "dev": "vite",  // 开启服务器
    "build": "vite build", // 打包
    "preview": "vite preview" //预览
  },

好处就是很快,非常快。原因是用原生esm模块化无需打包,还是按需引入。 但是不建议在项目中使用,因为需要配置的东西有很多。 项目中最好还是用脚手架和 webpack进行打包等工作。(关于如何搭建一个vite项目,看官网开始 | Vite (vitejs.net)

Vue3的组合式API

这里以一个简单的数字进行简介:

<template>
  <button @click="add">{{ count }}</button> //一个按钮实现点击对count加一的操作
</template>

<script>
// option 式api
// setup一开始就会调用,有点类似与选择式API的create函数
export default {
  setup() {
    let count = 1; //  声明count
    function add() {  //声明button的操作
      count++; 
      console.log(count);
    }
    return {  //这种写法必须写return 把数据方法和数据暴露出去
      count,
      add,
    };
  },
};
</script>
// 下面这种方法是对上面setup进行简写 不用再写return和setup,也就是上面代码块的语法糖
<!-- <script setup>
// option 式api
    let count = 1;
    function add() {
      count++;
      console.log(count);
    }
</script> -->

上面代码有个致命的问题,就是数据不是响应式的,试图无法与数据同步发生变化。此时需要一个新的api:ref对数据进行和操作进行包裹,代码如下:(需要注意的是,此时script代码块里数据和操作需要通过value属性来进行操作,但是渲染到试图不用写value属性)

<template>
  <button @click="add">{{ count }}</button>
</template>

<!-- <script>
// option 式api
  import {ref} from 'vue';
export default {
  setup() {
    let count = ref(1);
    function add() {
      count.value++;
      console.log(count.value);
    }
    return {
      count,
      add,
    };
  },
};
</script> -->
<script setup>
// option 式api
  import {ref} from 'vue'; // 引入新的api ref 对数据进行包裹
    let count = ref(1);
    function add() {
      count.value++;
      console.log(count.value);
    }
</script>

还有一个api reactive,是用来实现对象的响应式的,实现代码如下 :

<template>
  <button @click="add">{{ count }}</button> 
</template>

<script setup>
import {reactive} from 'vue' // 引入api
let count =reactive ({  // 包裹对象
  name:'zs',
  age:18
})
function add (){
  count.age++  // 实现操作
}
</script>

不过尽量reactive尽量不要使用了,原因很简单,ref即可以用于简单数据类型,也可以用于复杂数据类型,且性能更好,(ref底层做了优化) 将上面的代码可以改写成下面代码:

<template>
  <button @click="add">{{ count }}</button> 
</template>

<script setup>
import {ref} from 'vue';

let count =ref ({  // 通过ref对对象进行包裹实现响应式
  name:'zs',
  age:18
})
function add (){
  count.value.age++  // ref在使用时必须使用value
}
</script>

这里可以了解一下hook就是把多个组件中一样的逻辑提取出来例如data、methods。了解一下第三方的库 vueuse (VueUse | VueUse)。

有两个api是onmounted和onunmounted类似于vue2中的mounted挂载后和beforedestroy销毁前 ,示例如下:

<template>
<p>{{obj}}</p>
</template>

<script setup>
// 一般以下情况导致内存泄漏:定时器、全局变量、闭包、vue组件中监听的dom时间再组件销毁时候没有被移除
import {ref,onMounted,onUnmounted} from 'vue'
const obj = ref({
  x:0,
  y:0
})
let fn = function (e){
  obj.value.x=e.pageX
  obj.value.y=e.pageY
}
// 相当于vue2中的mounted
onMounted(()=>{
  document.documentElement.addEventListener('mousemove',fn) // 鼠标移动事件
})
// 相当于之前的beforeDestroy
onUnmounted(()=>{
  document.documentElement.removeEventListener('mousemove',fn)
})
</script>

计算属性computed函数,与vue2类似,代码实例如下 计算属性两种写法:一种就是计算属性里面写钩子函数,写产生变化的数据。另一种就是get和set的写法,get返回获取到的值,set返回本身变化对其他产生变换的值。(注意,不要再计算属性里面异步操作或者改变dom,想要进行这些操作,要卸载侦听器watch里面) :

<template>
  <div>今年的年纪 <input type="text" v-model="age" /></div>
  <div>明年的年龄 {{ nextAge }}</div>
  <div>后年的年龄 <input type="text" v-model="nextAge2" /></div>
  <div></div>
</template>

<script setup>
// 计算属性两种写法
import { computed, ref } from "vue";
const age = ref(20);
const nextAge = computed(() => { // 第一种写法 简单写法,是只读的
  return +age.value + 1;
});
const nextAge2 = computed({ // 第二种写法 也是完整写法,是双向的
  get() {
    return +age.value + 2;
  },
  set(value) {
    age.value = value - 2;
  },
});
</script>

监听器watch函数 watch监视, 接收三个参数:

  1. 参数1: 监视的数据源
  2. 参数2: 回调函数
  3. 参数3: 额外的配置

实例代码如下:

 <input type="text" v-model="name">
 <p :style="{ color : bool ?'green':'red'}">{{bool?'合法':'违法'}}</p>
</template>

<script setup>
import { watch, ref } from "vue"; 
let name = ref('')
let bool = ref(true)
watch(
  name, //数据源
  (val) => {  // 回调函数
    if (val.length < 3 || val.length > 8) {
      bool.value = false;
    } else {
      bool.value = true;
    }
  },
  {  额外配置
    deep: true,
    immediate: true,
  }
);
</script>

钩子函数: 常用的就四个 setup(ajax) onMounted(操作dom) onUpdated(拿到数据更新之后最新的DOM) onBeforeUnmount(移除定时器等)

组件的复用及传值

组件的局部调用,不再像vue2需要先进行注册再去使用,vue3里引用后直接使用。

<template>
<MyCeshi></MyCeshi>
</template>

<script setup>
import MyCeshi from './components/MyCeshi.vue'

</script>

组件间传值:

  • 父向子传值:子组件通过defineProps来接收,
<template>
{{car}}
</template>

<script setup>
//父组件给子组件传值 只需要再函数调用里加上一句 :car = '要传的数据'
const props = defineProps({ // 通过defineProps来接收,不用引入啥的
    car:{
        type:String,
        required: true
    }
})
console.log(props.car); 
</script>
  • 子向父传值:通过defineEmits发送
// 父组件 通过@myclick="fn"声明事件
<template>
  <MyCeshi @myclick="fn"></MyCeshi>
</template>

<script setup>
import MyCeshi from "./components/MyCeshi.vue";
function fn(val) {
  console.log('子向父传值'+val);
}
</script>

// 子组件  通过defineEmits和emit来进行操作 有两种写法
<template>
<button @click="$emit('myclick',200)">子向父传值</button>
<button @click="handleClick">另一种子向父传值方法</button>
</template>

<script setup>
const emit = defineEmits(['myclick']) //写法1
function handleClick(){ //写法2
    emit('myclick',300)
}
</script>

  • 兄弟组件传值:这个与vue2不同,不能通过eventbus来传值。vue3通过mitt第三方插件可实现组件间通信。 兄弟组件及一个mitt.js文件可以实现
//mitt.js文件
import mitt from 'mitt'  // 下载好mitt后引入
export default mitt() // 暴露mitt()方法

//两兄弟组件
//组件1
<template>
<button @click="btn">组件间传值</button>
</template>

<script setup>
import mitt from '../mitt'
function btn() {
    mitt.emit('my-event',200) 通过emit来发送数据
}
</script>
// 组件2
<script setup> 
import mitt from '../mitt'
mitt.on('my-event',(num)=>{  // 通过on来接收数据
    console.log(num);
})
</script>

  • 隔代传值 provide inject
  • 任意两个组件 不再用vuex而是使用pinia(菠萝)

通过ref获取元素

<template>
  <p ref="pRef">123645</p>
</template>
<script setup>
import { onMounted, ref } from "vue";
 const pRef = ref(null);
 onMounted(() => {
   console.log(pRef.value);  // 就获取到了元素
 });
 </script>

过滤器

再vue里,filter过滤器被废弃,取而代之的直接使用函数形式就可以了:

<template>
  <p>{{ format(money, "元") }}</p>  // 使用过滤器函数
</template>
<script setup>
import { ref } from "vue";
const money = ref(600)
function format(money, param) {  // 声明过滤器函数
  return money + param;
}
</script>