简单入门vue3小教程,需要vue2基础

88 阅读7分钟

vue3代码结构对比vue2的区别
1.template不需要根元素
2.使用createApp这个API来创建vue实例
3.可以在script标签上写setup,开启setup语法糖
4.template和script交换位置

vue3的优点:
1.更低的维护成本   1.组合式API2.发更好的TypeScript支持
2.更高的运行效率   1.新的diff算法2.模板编译优化3.更高效的组件初始化
3.更小的体积     1.良好的TreeShaking2.按需引入
4.使用proxy来实现数据响应式

vue3的生命周期
setup => onBeforeMount => onMounted => onBeforeUpdate => onUpdated => onBeforeUnmount => onUnmounted
简单来说,就是前面加个on,需要注意的是,vue3将beforeCreate和created合并为了setup,它执行于beforeCreat之前,在vue3中,distory改为unmount
使用生命周期钩子:

<script setup>
// 导入
import {onMounted} from 'vue'
// vue3的钩子可以写多个,因为是回调函数
onMounted(() => {
    函数语句
})
</script>

1.setup
 1.1 基本使用
setup(){}可以理解为钩子函数,是vue2中beforecreate和created合并而来的,它可以return出在其中定义的数据,这些数据可以在template中使用,但不是响应式的

<script>
export default {
  setup() {
    const message = 'nihao'
    const say = () => {
      console.log(message)
    }
    return {
      message,
      say
    }
  },
}
</script>

<template>
  <div @click="say">
    {{message}}
  </div>
</template>

 1.2 语法糖 <script setup />
在script标签上写setup属性,开启setup语法糖,script中的代码将自动识别并添加到setup钩子中,并自动return,导入的组件自动注册
但需要注意,在setup中this.指向undefined

以下代码效果与上面完全相同
<script setup>
    const message = '你好'
    const say = () => {
      console.log(message)
    }
</script>

<template>
  <div @click="say">
    {{message}}
  </div>
</template>

2.reactive
 2.1 导入
 2.1 定义,并使用,参数必须是对象

<script setup>
// 导入并注册
import {reactive} from 'vue'

// 定义响应式数据,注意,reactive的参数必须是一个对象,定义一个变量接收reactive函数的返回值
const state = reactive({
  count: 0
})

// 使用reactive的返回值调用内部数据并修改
const sum = () => {
  state.count++
}
</script>

<template>
  <div @click="sum">
    {{state.count}}
  </div>
</template>

3.ref
 3.1 导入
 3.2 定义,并使用,注意,在模板中不需要带value,在js中则必须要带

<script setup>
// 导入并注册
import {ref} from 'vue'

// 定义
const age = ref(17)
const happyBthDay = () => {
  console.log('happy happy happy');
  //需要用.value来获取ref的值
  age.value++
}
const message = ref({
  say: 'nihao'
})
const say = () => {
  message.value.sing = 'la la xi la so~'
  //对象的属性的取值方法
  console.log(message.value.sing)
}
</script>

<template>
  <header>
    <button @click="happyBthDay">
      {{age}}
    </button>
    <button @click="say">
      {{message.say}}
    </button>
  </header>
</template>

 3.3 对比 ref 和 reactive

a.reactive不能处理简单类型的数据
b.ref参数类型支持更好,但是必须通过.value做访问修改
c.ref本质上还是调用了reactive实现的

可以看源码cdn.bootcdn.net/ajax/libs/v…
内部实现是这样的:
function ref -> createRef -> new RefImpl -> constructor -> toReactive -> reactive

  1. 计算属性
     4.1 导入
     4.2 计算属性的定义
     4.3 使用
<script setup>
  // 导入
  import {ref, computed} from 'vue'
  
  // 定义一个用于测试的数组
  const arr = ref([1,2,3,4,5,6,7])
  
  // 定义一个计算属性,将数组中大于2的元素筛选出来
  const newArr = computed(() => {
    return arr.value.filter(item => {
      return item > 2
    })
  })
  
  // 添加一个数组的元素,测试计算属性能否响应式更新
  const add = () => {
    arr.value.push(10)
  }
</script>

<template>
  <header>
    <div>
      {{arr}}
      <button @click="add">补充一个元素 10</button>
    </div>
    <div>
      {{newArr}}
    </div>
  </header>
</template>

 4.4 传值

<script setup>
  // 导入
  import {ref, computed} from 'vue'
  
  // 定义用于测试的数组
  const arr = ref([1,2,3,4,5,6,7])
  const arr1 = ref([a,b,c,d,e,f,g])
  
  // 定义一个计算属性,根据参数返回一个对应字母表中的字母
  // 本质是计算属性返回了一个 返回结果的方法
  const str = computed(() => (item) => {
    return arr1[item-1]
  })
</script>

<template>
  <ul>
    <li v-for="item in arr">{{str(item)}}</li>
  </ul>
</template>
  1. watch
     5.1 导入watch
     5.2 使用watch侦听响应式的数据
     5.3 侦听多个值变化,将第一个参数改为数组,将需要侦听的数据都丢进去即可
     5.4 开启立即执行侦听器,可以写第三个参数,这个参数是个对象,里面有im属性,设置为true即可
     5.5 开启深度监听,watch默认只监听浅层,开启深度监听后,可以监听到深层数据,但它会遍历递归监听,导致性能的损耗
     5.6 在不开启deep的情况下,对对象中某个值进行精准监听,需要将第一个参数改为函数,并返回要监听的属性
<script setup>
// 1. 导入
import { ref, watch } from "vue";

  // 2. 定义一个基本数据
  const count = ref(17)
  
  // 3. 定义让该数据变化的方法
  const add = () => {
    count.value++
  }
  
  // 4. 定义一个监听器, 当count发生变化时,打印新值和旧值
  // 第一个参数是目标变量,不需要加value,第二个参数是回调,写监听到之后的处理函数
  watch(count, (newVal, oldVal) => {
    console.log('newVal: ' , newVal);
    console.log('oldVal: ' , oldVal);
  })
  
  // 5. 定义第二个测试数据和测试方法
  const age = ref(18)
  const addAge = () => {
    age.value++
  }
  
  // 6. 侦听多个变量
  watch([count, age], (newVal, oldVal) => {
    console.log('某个数据变化了');
    console.log('newVal: ' , newVal);
    console.log('oldVal: ' , oldVal);
  })
  
  // 7. 立即执行侦听器
  watch(count,  (newVal, oldVal) => {
    console.log('newVal: ' , newVal);
    console.log('oldVal: ' , oldVal);
  }, {
    immediate: true
  })
  
  // 8. 准备深度监听的测试数据和方法
  const obj = ref({
    a: 123
  })
  
  const changeA = () => {
    obj.value.a = 456
  }
  
   // 9. 开启深度侦听
  watch(obj,  (newVal, oldVal) => {
    console.log('newVal: ' , newVal);
    console.log('oldVal: ' , oldVal);
  }, {
    deep: true
  })
  
  // 10. 精准监听
  watch(() => obj.a,  (newVal, oldVal) => {
    console.log('newVal: ' , newVal);
    console.log('oldVal: ' , oldVal);
  })
  
</script>

<template>
  <header>
    <div>
      {{count}}
      <button @click="add">让count自增</button>
    </div>
    <div>
      {{age}}
      <button @click="addAge">让age自增</button>
    </div>
    <div>
      {{obj}}
      <button @click="changeA">改变obj中属性a的值</button>
    </div>
  </header>
</template>

注:在侦听pinia的ref数据时不需要加value!!!通宵半宿的教训啊!!!!!!!!

vue3的父子通信
一. 父传子
1.父组件中基本无变化
2.子组件接收需要用编译器宏 defineProps
3.如果需要在script标签内调用defineProps中的值,需要先用变量接收编译器宏的返回值

父组件:
<script setup>
import SonCom from '@/components/son-com.vue'
import { ref } from 'vue'

// 定义测试数据
const list = ref([1, 2, 3, 4])
const obj = ref({
  name: 'nengdie',
  habby: ['lashit', 'sleep']
})

// 定义一个定时器,3秒后操作数据,看看子组件是否成功接收,并响应式更新
setTimeout(() => {
  list.value.push(10)
}, 3000)

</script>

<template>
  <header>
    <SonCom :obj="obj" :list="list" message="nihao"></SonCom>
  </header>
</template>


子组件:
<template>
  <div>{{message}}</div>
  <div>{{list}}</div>
  <div>{{obj}}</div>
</template>

<script setup>
    // 用编译器宏接收父组件传来的值,在模板中可直接使用
    // 在代码中调用需要先用变量接收这个编译器宏的返回值
    const props = defineProps({
        message: String,
        list: Array,
        obj: Object
    })
    // 使用 编译器宏的返回值.值的变量名 来调用
    console.log(props.message);
</script>

二.子传父
1.在子组件中使用defineEmits注册需要上传的事件
2.使用emit('事件名', 值)来向父组件发出事件
3.字父组件定义该事件的处理函数,和vue2相同

父组件: 
<script setup>
// 1. 导入
import SonCom2 from '@/components/son-com2.vue'
import { ref } from 'vue';

// 2. 定义测试数据,以及接收处理函数
const message = ref('nihao')
const getMessage = (msg) => {
  console.log(msg);
  message.value = msg
}
</script>

<template>
  <header>
    <!-- 使用自定义事件接收 -->
    <SonCom2 @getMessage="getMessage"></SonCom2>
    {{message}}
  </header>
</template>


子组件:
<template>
  <div>
    <button @click="take">take message</button>
  </div>
</template>

<script setup>
    // 使用defineEmits声明自定义事件,并使用一个变量接收其返回值
    const emit = defineEmits(['getMessage'])
    
    // 定义传值的事件,点击按钮执行
    const take = () => {
        emit('getMessage', '你好')
    }
</script>

三.获取原生DOM或组件引用,并利用引用获取子组件的数据
1.利用defineExpose({数据1, 数据2,...})暴露子组件的数据,此时外界就可以通过ref获取的引用访问这个数据

子组件中:
<template>
  <div></div>
</template>

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

// 定义数据和方法以供父组件调用
const message = ref('nihao')
const changeMsg = () => {
    message.value = '你好'
}

// 对外暴露需要使用的数据和方法
defineExpose({message, changeMsg})
</script>

2.利用 ref 获取原生DOM或组件引用
3.利用引用拿值,或调用子组件的方法

父组件中:
<script setup>
// 1. 导入
import SonCom3 from '@/components/SonCom3.vue'
import { onMounted, ref } from 'vue';

2.定义一个空的ref数据,用以接收DOM或组件引用
const refCom3 = ref(null)

3. 在 onMounted 钩子中,通过获取已经挂载的组件引用调用子组件的数据和方法
onMounted(() => {
  // 打印子组件数据
  console.log(refCom3.value.message)
  // 调用子组件方法
  refCom3.value.changeMsg()
  // 打印新数据
  console.log(refCom3.value.message)

})
</script>

<template>
  <header>
    <!-- 通过ref属性获取引用 -->
    <SonCom3 ref="refCom3"></SonCom3>
  </header>
</template>

四.使用provideinject

  1. 祖先传后代
     1.1.顶层通过 provide 提供数据
     1.2.底层通过 inject 接收数据

2.后代修改祖先的数据
 2.1祖先传一个修改数据的方法
 2.2将该方法通过 provide 传到底层
 2.3底层使用 inject 接收并调用

结构:  祖先组件 => 子组件 => 孙组件

顶层组件/祖先组件
<script setup>
// 1. 导入
import MySon from './components/MySon.vue';
import { provide, ref } from 'vue';

// 2. 定义测试数据
const message = ref('nihao')

// 3. 定义修改数据的方法
const changeMessage = () => {
  message.value = '你好'
}

// 4. 通过provide提供数据
provide('message', message)
provide('i18n', changeMessage)
</script>

<template>
  <div>
    <MySon></MySon>
  </div>
</template>


底层组件/孙组件
<template>
    <div>{{message}}</div>
    <button @click="change">change</button>
</template>

<script setup>

// 导入
import { inject } from "vue";

// 通过inject接收数据
const message = inject('message')

//接受改变祖先组件数据的方法并通过按钮调用
const i18n = inject('i18n')
const change = () => {
    i18n()
}
</script>