Vue3入门

认识Vue3

1. Vue2 选项式 API vs Vue3 组合式API

<script>
export default {
  data(){
    return {
      count:0
    }
  },
  methods:{
    addCount(){
      this.count++
    }
  }
}
</script>
<script setup>
import { ref } from 'vue'
const count = ref(0)
const addCount = ()=> count.value++
</script>

特点:

  1. 代码量变少
  2. 分散式维护变成集中式维护

2. Vue3的优势

在这里插入图片描述

使用create-vue搭建Vue3项目

1. 认识create-vue

create-vue是Vue官方新的脚手架工具,底层切换到了 vite (下一代前端工具链),为开发提供极速响应

在这里插入图片描述

2. 使用create-vue创建项目

前置条件 - 已安装16.0或更高版本的Node.js

执行如下命令,这一指令将会安装并执行 create-vue

npm init vue@latest

在这里插入图片描述

使用npm初始化项目之后,再cd到项目目录

cd 项目名

cd到项目目录之后,再使用npm安装一些依赖

npm install

最后让项目跑起来,如果不遵循上面的规矩的化可能会出现很多的问题

npm run dev

熟悉项目和关键文件

在这里插入图片描述

在vue3中对创建对象进行了一定的封装,使用creat来进行创建对象。比如下面例子。

main.js

import './assets/main.css'

// new Vue()创建一个应用实例 => createApp()
// createRouter() createStore()
//将创建实例进行了封装,保证每个实例的独立封闭性,但是需要引入对应的函数才行。

import { createApp } from 'vue'
import App from './App.vue'

// mount设置挂载点#app (id为app的盒子),可以理解为前段为创建App这个对象,后半段为将这个App对象直接挂载到id为app的盒子上去
createApp(App).mount('#app')

组合式API - setup选项

<!-- 加上setup允许在script中直接编写组合式API !-->
<script setup>
import HelloWorld from './components/HelloWorld.vue'
import TheWelcome from './components/TheWelcome.vue'
</script>

<template>
<!-- 在vue3中可以不用注册组件直接使用导入的组件 --!>
<--不再要求唯一根元素-->
  <header>
    <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />

    <div class="wrapper">
      <HelloWorld msg="You did it!" />
    </div>
  </header>

  <main>
    <TheWelcome />
  </main>
</template>

<style scoped>
header {
  line-height: 1.5;
}

.logo {
  display: block;
  margin: 0 auto 2rem;
}

@media (min-width: 1024px) {
  header {
    display: flex;
    place-items: center;
    padding-right: calc(var(--section-gap) / 2);
  }

  .logo {
    margin: 0 2rem 0 0;
  }

  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }
}
</style>

1. setup选项的写法和执行时机

写法

<script setup>
  export default {
    setup(){
      
    },
    beforeCreate(){
      
    }
  }
</script>

执行时机

在beforeCreate钩子之前执行

在这里插入图片描述

<script> 
// setup
// 1.执行时机,比beforeCreate还要早
// 2. setup函数中,获取不到this (this是undefined),因为setup的执行时间比beforeCreate生命周期函数还要早
// this是基于当时的环境来看到底是指向谁的。在vue3中可以不用纠结this的指向了,因为vue3中很少再使用this了
    export default {
		setup ({
			console.1og(' setup函数',this)
    	},
		beforeCreate ( {
			console.log( 'beforeCreate函数')
    	}
	}
</script>
<template>
	<div>学习Vue3</div>
</template>

2. setup中写代码的特点

在setup函数中写的数据和方法需要在末尾以对象的方式return,才能给模版使用

<script>
  export default {
    setup(){
      // setup中可以提供数据,也可以提供方法,但是只有return对应的数据和方法之后才可以在模板中使用。
      const message = 'this is message'
      const logMessage = ()=>{
        console.log(message)
      }
      // 必须return才可以再模板中使用这个数据
      return {
        message,
        logMessage
      }
    }
  }
</script>
<template>
	<div>{{ message }}</div>
</template>
// 这样就出现了一个问题,如果需要return多个数据或者函数,就需要一个一个return,这样做非常的麻烦。于是就出现了setup的语法糖

3.

script标签添加 setup标记,不需要再写导出语句,默认会添加导出语句

<script setup>
  const message = 'this is message'
  const logMessage = ()=>{
    console.log(message)
  }
</script>

组合式API - reactive和ref函数

在vue中,数据并不是响应式的如果需要将数据变成响应式的需要使用reactive函数和ref函数。

1. reactive

接受对象类型数据的参数传入并返回一个响应式的对象

<script setup>
 // reactive: 接受对象类型数据的参数传入并返回一个响应式的对象
 // 如果是简单类型的数据该怎么办呢?可以使用ref函数。
 // 导入
 import { reactive } from 'vue'
 // 执行函数 传入参数 变量接收
 const state = reactive({
   msg:'this is msg'
 })
 const setSate = ()=>{
   // 修改数据更新视图
   state.msg = 'this is new msg'
 }
</script>

<template>
  {{ state.msg }}
  <button @click="setState">change msg</button>
</template>

2. ref

接收简单类型或者对象类型的数据传入并返回一个响应式的对象

<script setup>
 // 导入
 import { ref } from 'vue'
 // 执行函数 传入参数 变量接收
 // ref的本质:是在原有传入数据的基础上,外层包了一层对象,包成了复杂类型
 // ref的底层:包成复杂类型之后,再借助 reactive 实现的响应式
 // 注意点:
 // 1.脚本 script 中访问数据,需要通过.value
 // 2.在template中, .value不需要加(帮我们扒了一层)
 // ref 的底层也是使用 reactive 函数
    
 // 由于同时使用 reactive 函数和 ref 函数会造成混乱,于是就有一个统一的规定,那就是统一使用 ref 函数
 // 因为 ref 函数可以同时将普通类型和复杂类型的数据变成响应式的。
 const count = ref(0)
 const setCount = ()=>{
   // 修改数据更新视图必须加上.value
   count.value++
 }
</script>

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

3. reactive 对比 ref

  1. 都是用来生成响应式数据
  2. 不同点
    1. reactive不能处理简单类型的数据
    2. ref参数类型支持更好,但是必须通过.value做访问修改
    3. ref函数内部的实现依赖于reactive函数
  3. 在实际工作中的推荐
    1. 推荐使用ref函数,减少记忆负担,小兔鲜项目都使用ref

组合式API - computed

计算属性基本思想和Vue2保持一致,组合式API下的计算属性只是修改了API写法

语法:

const 计算属性 = computed(()=>{
    return 计算返回的结果;
})

const count = computed(()=>{
    return count*2;
});
<script setup>
// 导入
import {ref, computed } from 'vue'
// 原始数据
const count = ref(0)
// 计算属性
const doubleCount = computed(()=>count.value * 2)

// 原始数据
const list = ref([1,2,3,4,5,6,7,8])
// 基于list派生一个计算属性,从list中过滤出 > 2 的数据
const newFilterList = computed(()=>{
    return list.value.filter((elem)=> elem > 2 );
    // 注意这里的list的属性值之一value才是真正的目标数组
})

const filterList = computed(item=>item > 2)

const addFn() = ()=>{
    list.value.push(111);
}
</script>

<template>
	<div>
    	<div>原始数据: {{ list }</div>
		<div>计算后的数据: {{ newFilterList }}</div>
        <button type="button" @click="addFn">修改</ button>
    </div>
</template>

vue3中的computed函数的计算属性也是和vue2中的计算属性是差不多的,也是有get和set函数的,不可以随便的修改计算属性的值,否则会直接报错的。详细的内容可以直接去官网上查看。通过ref创建的计算属性原值,得到的是一个只读的属性。

计算属性中不可以有副作用,比如说:异步请求和修改dom的操作。

组合式API - watch

侦听一个或者多个数据的变化,数据变化时执行回调函数,俩个额外参数 immediate控制立刻执行,deep开启深度侦听

1. 侦听单个数据

语法:

watch(ref对象, (newValue, oldValue)=>{...});
// 注意第一个参数一定是一个ref对象,不可以是ref对象的value值比如说:ref对象.value
<script setup>
  // 1. 导入watch
  import { ref, watch } from 'vue'
  const count = ref(0)
  // 2. 调用watch 侦听变化
  watch(count, (newValue, oldValue)=>{
    console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
  })
</script>

2. 侦听多个数据

侦听多个数据,第一个参数可以改写成数组的写法

<script setup>
  // 1. 导入watch
  import { ref, watch } from 'vue'
  const count = ref(0)
  const name = ref('cp')
  // 2. 调用watch 侦听变化
  watch([count, name], ([newCount, newName],[oldCount,oldName])=>{
    console.log(`count或者name变化了,[newCount, newName],[oldCount,oldName])
  })
</script>

3. immediate

在侦听器创建时立即出发回调,响应式数据变化之后继续执行回调

<script setup>
  // 1. 导入watch
  import { ref, watch } from 'vue'
  const count = ref(0)
  // 2. 调用watch 侦听变化
  watch(count, (newValue, oldValue)=>{
    console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
  },{
    immediate: true
  })
</script>

4. deep

通过watch监听的ref对象默认是浅层侦听的,直接修改嵌套的对象属性不会触发回调执行,需要开启deep

语法:

// 4. deep深度监视,默认watch进行的是浅层监视
// const ref1 = ref(简单类型)可以直接监视
// const ref2 = ref(复杂类型)监视不到复杂类型内部数据的变化
watch(ref对象, (newValue, oldValue)=>{...},{deep:true});
<script setup>
  // 1. 导入watch
  import { ref, watch } from 'vue'
  const state = ref({ count: 0 })
  // 2. 监听对象state
  watch(state, ()=>{
    console.log('数据变化了')
  })
  const changeStateByCount = ()=>{
    // 直接修改不会引发回调执行
    state.value.count++
  }
  // 这种情况只有修改了state的整个地址,watch函数才可以监视到,
  // 比如说:
  // state = ref({name: 'tom'})
  // state.value = {name: 'tom'}
  // 这样的情况watch函数才可以直接监视到
</script>

<script setup>
  // 1. 导入watch
  import { ref, watch } from 'vue'
  const state = ref({ count: 0 })
  // 2. 监听对象state 并开启deep
  watch(state, ()=>{
    console.log('数据变化了')
  },{deep:true})
  const changeStateByCount = ()=>{
    // 此时修改可以触发回调
    state.value.count++
  }
</script>

5.精确监视

可以直接监视一个对象的具体的某个值

const userInfo = ref({
    name: 'tom',
    age: 10
});

watch(
    () => userInfo.value.age, 
    (newValue,oldvalue) => {
    	console.log(newValue,oldValue);
});

组合式API - 生命周期函数

1. 选项式对比组合式

在这里插入图片描述

这里的意思就是:以前的写在选项式中的API生命周期对应到组合式API中是相应的生命周期函数,比如说:选项式的beforeCreate和created生命周期函数对应到组合式API中的生命周期函数是setup函数,只要将对应的选项式API中的生命周期函数写道组合式API对应的生命周期函数中就行了。

2. 生命周期函数基本使用

  1. 导入生命周期函数
  2. 执行生命周期函数,传入回调
<scirpt setup>
import { onMounted } from 'vue'
onMounted(()=>{
  // 自定义逻辑
})
</script>

3. 执行多次

生命周期函数执行多次的时候,会按照顺序依次执行

<scirpt setup>
import { onMounted } from 'vue'
onMounted(()=>{
  // 自定义逻辑
})

onMounted(()=>{
  // 自定义逻辑
})
</script>

组合式API - 父子通信

1. 父传子

由于写了steup,所以无法直接配置 props 选项,所以就使用vue3提供的 编译器宏来完成。

基本思想

  1. 父组件中给子组件绑定属性
  2. 子组件内部通过props选项接收数据

注意:

vue3父传子属性的方式和vue2是相同的,vue3对于直接赋值的属性可以不用在属性的前面添加 : 但是传入的值如果是父组件的某一个数据,就需要在传入的属性前面添加 : 比如说:,name属性传入的是固定值,不需要添加 : 但是age传入的是父组件的某一个属性就需要在前面添加 :

对于props传过来的数据,在模板template中可以直接通过名称使用,但是在script脚本中只能通过 对象.属性名 的方式获取对应的值。

在这里插入图片描述

2. 子传父

基本思想

  1. 父组件中给子组件标签通过@绑定事件
  2. 子组件内部通过 emit 方法触发事件

父组件给子组件添加事件的方式还是一样的,但是子组件触发父组件的方式还是和vue2有一点区别的。比如说:子组件必须通过defineEmit编译器宏的方式来生成emit,注意,在vue3中不在emit前面添加this和$了,直接使用就行了,但是,在使用之前必须在编译器宏defineEmit里面注册。

在这里插入图片描述

组合式API - 模版引用

概念:通过 ref标识 获取真实的 dom对象或者组件实例对象

1. 基本使用

实现步骤:

  1. 调用ref函数生成一个ref对象
  2. 通过ref标识绑定ref对象到标签
  3. 对象.value就可以在脚本script中使用这个绑定的元素了。

注意:

必须要在dom元素渲染完成之后才可以进行绑定,否则就是undefined。

在这里插入图片描述

比较全面的写法如下:

<script>
import { ref } from 'vue';
const inp = ref(null);
    
onMounted(()=>{
    inp.value.focus(); // 一进入页面就聚焦
});
    
console.log(inp.value); // 这样打印是不行的,因为dom在这个时候还没有渲染完成

const clickFn = () => {
    inp.value.focus(); // 点击之后就聚焦
}

// 下面是通过ref获取子组件,尝试使用子组件数据和函数
const testCom = ref(null);
    
onMounted(()=>{
    console.log(testCom); // 这样做虽然会打印出testCom子组件对象,但是无法在子组件对象中找到子组件的方法和数据。
})
</script>

<template>
	<div>
		<input ref="inp" type="text">
        <button @click="clickFn">点击让输入框聚焦</button>
    </div>
	<Testcom ref="testCom"></TestCom>
	<button>获取组件</button>
</template>

注意:

默认情况下在

可以通过defineExpose编译宏指定子组件中的哪些属性和方法允许访问

2. defineExpose

默认情况下在

在这里插入图片描述

使用defineExpose指定子组件传递出的数据,在父组件中也可以修改,但是这样好像不太符合编程的规范。比如说,谁的数据就由谁来维护,哪个组件的数据就由哪个组件来维护。

组合式API - provide和inject

1. 作用和场景

顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信

在这里插入图片描述

2. 跨层传递普通数据

实现步骤

  1. 顶层组件通过 provide 函数提供数据
  2. 底层组件通过 inject 函数提供数据

在这里插入图片描述

3. 跨层传递响应式数据

在调用provide函数时,第二个参数设置为ref对象

在这里插入图片描述

4. 跨层传递方法

顶层组件可以向底层组件传递方法,底层组件调用方法修改顶层组件的数据

在这里插入图片描述

有了vue3之后,非父子之间的传递数据和传递方法就方便多了,不用再像vue2一样,使用 provideinject 来传递数据,使用 eventbus 事件总线来传递修改数据的方法。vue3的 provide 就同时拥有了这两个特性,既可以传递数据也可以传递修改数据的方法。

Vue3.3 新特性-defineOptions

背景说明:

但是用了


为了解决这一问题,引入了 defineProps 与 defineEmits 这两个宏。但这只解决了 props 与 emits 这两个属性。

如果我们要定义组件的 name 或其他自定义的属性,还是得回到最原始的用法——再添加一个普通的

这样就会存在两个

比如说:

// 这是在没有引入新特性defineOptions之前的写法,如果vue文件的名字太短,就需要在script脚本中自己添加name属性
// 但是在setup的script脚本中无法添加name属性,于是就出现了另外添加一个script脚本,用来添加其他的和setup同级的属性
// 比如说name属性,和其他的没有宏函数的钩子函数。
// 这样做会显得非常的奇怪,一个vue文件中出现了两个script脚本。于是就出现了vue3的新特性来解决这个问题。
<script>
export default {
	name: 'RegisterIndex'
}
</script>

<script setup>

</script>
<template>
	<div>
		我是注册页
	</div>
</template>

所以在 Vue 3.3 中新引入了 defineOptions 宏。顾名思义,主要是用来定义 Options API 的选项。可以用 defineOptions 定义任意的选项, props, emits, expose, slots 除外(因为这些可以使用 defineXXX 来做到)

在这里插入图片描述

Vue3.3新特性-defineModel

在Vue3中,自定义组件上使用v-model, 相当于传递一个modelValue属性,同时触发 update:modelValue 事件

在这里插入图片描述

我们需要先定义 props,再定义 emits 。其中有许多重复的代码。如果需要修改此值,还需要手动调用 emit 函数。

于是乎 defineModel 诞生了。

在这里插入图片描述

在defineModel出现之前父组件对子组件使用 v-model 简化代码的写法:

父组件:

<script setup>
import MyInput from '@/components/my-input.vue'
import { ref } from 'vue'
const txt = ref('123456')
</script>

<template>
<div>
<MyInput v-model="txt"></MyInput>
    {{ txt }}
</div>
</template>

子组件:

<script setup>
defineProps({
	modelValue: String
})
const emit = defineEmits(['update:modelvalue'])
</script>
<template>
<div>
	<input
	type="text"
	:value="modelValue"
	@input="e => emit('update:modelValue', e.target.value)"
</div>
</template>

使用了defineModel宏定义的子组件写法:

<script setup>
import { defineModel } from 'vue'
const modelValue = defineMode1()
</script>
<template>
<div>
	<input
	type="text"
	:value="modelValue"
	input="e => modelValue = e.target.value"
</div>
</template>

生效需要配置 vite.config.js

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue({
      script: {
        defineModel: true
      }
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})
  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值