Vue3

# 快速开始

vue3 现状介绍

了解:vue3 的现状以及它特点

  1. Vue3 的现状

2020 年 9 月 18 日发布,许多开发者还在观望。

2022 年 2 月 7 日称为默认版本,意味着 vue3 是现在也是未来。

库名称 简介
ant-design-vue PC 端组件库:Ant Design 的 Vue 实现,开发和服务于企业级后台产品
arco-design-vue PC 端组件库:字节跳动出品的企业级设计系统
element-plus PC 端组件库:基于 Vue 3,面向设计师和开发者的组件库
Naive UI PC 端组件库:一个 Vue 3 组件库,比较完整,主题可调,使用 TypeScript,快,有点意思
vant 移动端组件库:一个轻量、可靠的移动端组件库,于 2017 年开源
VueUse 基于 composition 组合式 api 的常用函数集合
  1. 相关文档

    1. Vue3 中文文档(新) cn.vuejs.org/
    2. Vue2 中文文档(旧) v2.cn.vuejs.org/
    3. Vue3 设计理念 vue3js.cn/vue-composi...
  2. 了解框架优点特点

    1. 首次渲染更快
    2. diff 算法更快
    3. 内存占用更少
    4. 打包体积更小
    5. 更好的 Typescript 支持
    6. Composition API 组合 API

总结: 学习 vue3 主要学习 组合式API 的使用。

vite 构建工具

了解:vite 工具作用和特点

vite(法语意为 "快速的",发音 /vit/,发音同 "veet") 是一种新型前端构建工具,能够显著提升前端开发体验。

对比 webpack:

  • 需要查找依赖,打包所有的模块,然后才能提供服务,更新速度会随着代码体积增加越来越慢

vite 的原理:

  • 使用原生 ESModule 通过 script 标签动态导入,访问页面的时候加载到对应模块编译并响应

注明:项目打包的时候最终还是需要打包成静态资源的,打包工具 Rollup

问题:

  • 基于 webpack 构建项目,基于 vite 构建项目,谁更快体验更好?vite
  • 基于 webpackvue-cli 可以创建 vue 项目吗?可以,慢一点而已

vite 创建项目

掌握:使用 vite 构建工具创建项目

  1. 运行创建项目命令:
perl 复制代码
# 使用npm
npm create vite@latest
# 使用yarn
yarn create vite
# 使用pnpm
pnpm create vite
  1. 输入项目名称,默认是 vite-project
  1. 选择前端框架
  1. 选择项目类型
  1. 创建完毕
  1. 进入项目目录,安装依赖,启动项目即可

代码分析

对 vite 初始化的代码进行分析

  1. 需要切换插件

vue3 组件代码和 vue2 有些不一样,使用的语法提示和高亮插件也不一样。

  • vetur 插件需要禁用,安装 volar插件。
  1. 总结 vue3 写法不同

    1. 组件一个根节点非必需
    2. 创建应用挂载到根容器
    3. 入口页面,ESM 加载资源

平常组件

xml 复制代码
<template>
  <div>节点1</div>
  <div>节点2</div>
</template>

main.js

javascript 复制代码
import { createApp } from 'vue'
import App from './App.vue'
// 根据App组件创建一个应用实例
const app = createApp(App)
// app应用挂载(管理)index.html的 #app 容器
app.mount('#app')

index.html

xml 复制代码
<div id="app"></div>
<script type="module" src="/src/main.js"></script>

总结:

  • 安装 volar 禁用 vuter,也可以使用工作区模式启用对应插件
  • vue3 中是使用 createApp() 管理容器,不是 new Vue()

组合式API介绍

介绍:什么是组合式API,组合式API的特点

Vue3提供两种组织代码逻辑的写法:

  • 通过data、methods、watch 等配置选项组织代码逻辑是选项式API写法
  • 所有逻辑在setup函数中,使用 ref、watch 等函数组织代码是组合式API写法

准备了两份代码实现同一些功能,做对比:

option api

xml 复制代码
<template>
  <button @click="toggle">显示隐藏图片</button>
  <img v-show="show" alt="Vue logo" src="./assets/logo.png" />
  <hr />
  计数器:{{ count }} <button @click="increment">累加</button>
</template>
<script>
export default {
  data() {
    return {
      show: true,
      count: 0,
    };
  },
  methods: {
    toggle() {
      this.show = !this.show;
    },
    increment() {
      this.count++;
    },
  },
};
</script>

composition api

xml 复制代码
<template>
  <button @click="toggle">显示隐藏图片</button>
  <img v-show="show" alt="Vue logo" src="./assets/logo.png" />
  <hr />
  计数器:{{ count }} <button @click="increment">累加</button>
</template>
<script>
// ref 就是一个组合式API  
import { ref } from 'vue';
export default {
  setup () {
    // 显示隐藏
    const show = ref(true)
    const toggle = () => {
      show.value = !show.value
    }
    // 计数器
    const count = ref(0)
    const increment = () => {
      count.value ++
    }

    return { show, toggle, count, increment }
  }
};
</script>

总结

  • 在setup中通过vue提供的内置函数组合,实现代码功能,就是组合式API写法。
  • 组合式API有什么好处?可复用,可维护
  • ref 是不是一个组合式API?是

setup函数

setup函数是组合式API的入口函数

  • setup 函数是 Vue3 特有的选项,作为组合式API的起点
  • 函数中 this 不是组件实例,是 undefined
  • 如果数据或者函数在模板中使用,需要在 setup 返回
xml 复制代码
<template>
  <div class="container">
    <h1 @click="say()">{{msg}}</h1>
  </div>
</template>

<script>
export default {
  setup () {
    console.log('setup执行了')
    console.log(this)
    // 定义数据和函数
    const msg = 'hi vue3'
    const say = () => {
      console.log(msg)
    }
    // 返回给模板使用
    return { msg , say}
  }
}
</script>

总结:

  • 今后在vue3的项目中几乎用不到 this , 所有的东西通过函数获取

setup语法糖

简化 setup 固定套路代码 ,让代码更简洁

发现:

  • 使用 setup 有几件事必须做:默认导出配置选项,setup函数声明,返回模板需要数据与函数。
xml 复制代码
<template>
  <div class="container">
    <h1 @click="say()">{{msg}}</h1>
  </div>
</template>

<script>
export default {
  setup () {
    console.log(this)
    // 定义数据和函数
    const msg = 'hi vue3'
    const say = () => {
      console.log(msg)
    }
    // 返回给模板使用
    return { msg , say}
  }
}
</script>

解法:

xml 复制代码
<script setup>
  const say = () => console.log('hi')
</script>

案例:体验一下

xml 复制代码
<template>
  <div class="container">
    <h1 @click="say()">{{msg}}</h1>
  </div>
</template>

<script>
// 定义数据和函数
    const msg = 'hi vue3'
    const say = () => {
      console.log(msg)
    }
</script>

小结:

  • script setup 中声明的变量都可以在模板使用,数据,函数,组件。
  • 不需要export default
  • 不需要return

了解-reactive函数

通常使用它定义 对象或数组 类型 响应式数据

疑问:以前在 data 函数中返回对象数据就是响应式的,现在 setup 中返回对象数据是响应式的吗?

  • 不是,需要使用 reactive 转成响应式

使用步骤:

  1. vue中导出reactive` 函数
  2. 调用用 reactive 函数,传入一个普通对象或数组,返回一个响应式数据对象或数组
xml 复制代码
<template>
  <div>
    <p>姓名:{{state.name}}</p>
    <p>年龄:{{state.age}} <button @click="state.age++">一年又一年</button></p>
  </div>
</template>

<script>
  
// 1. 导入函数
import { reactive } from "vue"; 
// 2. 创建响应式数据对象
const state = reactive({ name: 'tom', age: 18 })
    
</script>

总结:

  • reactive 函数通常定义:复杂类型的响应式数据
  • 可以转换简单数据吗?不能

ref函数

通常使用它定义响应式数据,不限类型

使用步骤:

  1. vue 中导出 ref 函数

  2. 调用 ref 函数,传入普通数据(简单or复杂),返回一个响应式数据

  3. 使用 ref 创建的数据,

    1. js 中需要 .value
    2. template 省略.value

落地代码:

xml 复制代码
<template>
  <div>
    <p>
      计数器:{{ count }}
      <button @click="count++">累加1</button>
      <!-- 4. template中使用可省略.value -->
      <button @click="increment">累加10</button>
    </p>
  </div>
</template>

<script>
// 1. 导入函数
import { ref } from "vue";
  
// 2. 创建响应式数据对象
const count = ref(0);
const increment = () => {
      
// 3.js中使用需要.value
count.value += 10;
  
};
</script>

总结:

  • ref 可以把简单数据或者复杂数据转换成响应式数据,

  • 注意

    • JS中使用加上 .value
    • 模板中使用省略.value

reactive 与 ref 的选择

知道:在定义响应式数据的时候如何选择reactive和ref

疑问:定义响应式数据使用 ref 还是 reactive 呢?

开始分析:

  • reactive 可以转换对象成为响应式数据对象,但是不支持简单数据类型。
  • ref 可以转换简单数据类型为响应式数据对象,也支持复杂数据类型,但是操作的时候需要 .value
  • 它们各有特点,现在也没有最佳实践,没有明显的界限,所有大家可以自由选择。

推荐用法:

  • 推荐:使用ref

参考代码:

xml 复制代码
<template>
  <div>
    <h1>{{ form.age }}</h1>
    <button @click="form.age++">reactive age++</button>

    <h1>{{ form.name }}</h1>
    <button @click="form.name += '~'">reactive name+~</button>
    <hr>
    <h1>{{ data.age }}</h1>
    <button @click="data.age++">ref age++</button>

    <h1>{{ data.name }}</h1>
    <button @click="data.name += '~'">ref name+~</button>
  </div>
</template>

<script setup>
import { reactive, ref } from 'vue'

let form = reactive({})
// 💥💥 重新赋值会导致响应式丢失
form = {
  name: 'zs',
  age: 18,
}


let data = ref({})
// 👍👍 重新赋值不会导致响应式丢失
data.value = {
  name: 'zs',
  age: 18,
}
</script>

<style lang="scss" scoped>
</style>

总结:

  • 尽量使用 ref 函数支持所有场景,减少心智负担。
  • 确定字段的对象使用 reactive 可以省去.value

computed函数

掌握:使用 computed 函数定义计算属性

作用:与vue2一模一样,根据其它数据计算得到一个新的值。

语法:computed( () => 返回一个新的值 )

大致步骤:

  • vue 中导出 computed 函数
  • 调用 computed 函数,传入一个回调函数,
  • 回调函数内计算新的值,并返回

静态结构:直接复制

xml 复制代码
<script setup>
  import { ref } from "vue";
  const score = ref()
	const scoreList = ref([50, 80, 100, 90, 70, 60])

  // 需求:定义三个计算属性,
  // 不及格 < 60
  const failList = []

  // commonList 及格 >=60 且 <90
  const commonList = [];

  // 优秀 > 90
  const betterList = []

</script>

<template>
  <div>
    <input type="text" v-model.number="score"><button @click="scoreList.push(score)">添加</button>
    <hr>
    <p>不及格: {{ failList  }}</p>
    <p>及格: {{ commonList }}</p>
    <p>优秀:{{ betterList }}</p>
  </div>
</template>

落地代码:

javascript 复制代码
const failList = computed(() => {
  // 💥💥注意: 回调函数,一定要有返回值
  return scoreList.value.filter((item) => item < 60)
})

// commonList 及格 >=60 且 <90
const commonList = computed(() => {
  // 💥💥注意: 回调函数,一定要有返回值
  return scoreList.value.filter((item) => item >= 60 && item < 90)
})

// 优秀 > 90
const betterList = computed(() => scoreList.value.filter((item) => item >= 90))

总结:

  • 作用:与vue2相同
  • 语法:computed( () => 返回一个新的值 )
  • 注意:💥回调函数一定要有返回值

watch函数

掌握:使用watch函数监听数据的变化

大致内容:

  • 使用 watch 监听一个基础数据类型
  • 使用 watch 监听一个复杂数据类型,配置深度监听
  • 使用 watch 监听,配置立即执行
  • 使用 watch 同时监听多个响应式数据
  • 使用 watch 只监听对象数据中的某一个属性(简单)
  • 使用 watch 只监听响应式对象数据中的一个属性(复杂),配置深度监听

语法:

  1. watch(基本数据,(newValue, oldValue) => { })
  2. watch(复杂数据,(newValue, oldValue) => { }, {deep: true, immediate: true})
  3. watch( [数据1, 数据2], (newValue, oldValue) => { })
  4. watch( () => 复杂数据.属性名, (newValue, oldValue) => { } )

静态结构:直接复制

xml 复制代码
<template>
  <div>计数器:{{ count }} <button @click="count++">count++</button></div>
  <div>
    <p>姓名:{{ user.name }}</p>
    <p>性别:{{ user.info.gender }}</p>
    <p>年龄:{{ user.info.age }}</p>
    <button @click="user.name += '~'">对象改名字</button>
    <button @click="user.info.age++">对象改年龄</button>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue'

const count = ref(0)
const user = ref({
  name: 'jack',
  info: {
    gender: '男',
    age: 18,
  },
})
</script>

落地代码:

javascript 复制代码
// 1. 基本数据类型
watch(count, (nVal, oVal) => {
  // 执行这个函数
  console.log(nVal, oVal)
})

// 2. 复杂数据类型
watch(user, (nVal, oVal) => {
  // 执行这个函数
  console.log('复杂数据类型  ----->  ', nVal );
}, {deep: true, immediate: true})

// 3. 同时监听多个数据
watch([count, user], (nVal, oVal) => {
  // 执行这个函数
  console.log('复杂数据类型  ----->  ', nVal );
}, {deep: true, immediate: true})
  • 使用 watch 监听响应式对象数据中的一个属性(简单)
  • 使用 watch 监听响应式对象数据中的一个属性(复杂),配置深度监听
javascript 复制代码
watch(() => user.value.name, (nVal) => {
  console.log('对象的某个属性  ----->  ', nVal );
})

watch(() => user.value.info, (nVal) => {
  console.log('对象的某个属性  ----->  ', nVal );
}, { deep: true })

总结:

  • watch(需要监听的数据,数据改变执行函数,配置对象) 来进行数据的侦听

  • 数据:

    • 单个数据
    • 多个数据
    • 对象的某个属性,函数返回对象属性,
    • 属性复杂需要开启深度监听
  • 配置对象:deep 深度监听 immediate 默认执行

生命周期函数

掌握:vue3的常用生命周期函数

使用步骤:

  1. 先从vue中导入以on打头的生命周期钩子函数
  2. 在setup函数中调用生命周期函数并传入回调函数
  3. 生命周期钩子函数可以调用多次

具体内容:

  • Vue3和vue2的生命周期对比
选项式API下的生命周期函数使用 组合式API下的生命周期函数使用
beforeCreate 不需要(直接写到setup函数中)
created 不需要(直接写到setup函数中)
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeDestroyed onBeforeUnmount
destroyed onUnmounted
activated onActivated
deactivated onDeactivated
  • 参考代码
xml 复制代码
<script setup>
  import { onBeforeUpdate, onMounted, onUpdated, ref } from "vue";
  const count = ref(0)
  
  onMounted(()=>{
    console.log('onMounted也触发了')
  })
  
  onBeforeUpdate(() => {
    console.log('更新前  ----->  ', );
  })
  onUpdated(() => {
    console.log('更新后  ----->  ', );
  })


</script>

<template>
  <span>{{ count }}</span> <button @click="count++">+1</button>
  <div>生命周期函数</div>
</template>

总结:

  • 发请求: onMounted
  • 语法:钩子函数(() => {})

ref获取DOM元素

元素上使用 ref属性关联响应式数据,获取DOM元素

步骤:

  1. 创建 ref:const xxxRef = ref()
  2. 绑定ref属性到标签上: ref="xxxRef"
  3. 通过xxxRef.value访问dom

代码:

xml 复制代码
<script setup>
import { ref } from 'vue'

// 1. 调用ref函数
const iptRef = ref()  
const clickFn = () => {
  console.log('iptRef  ----->  ', iptRef);
  // 通过`xxxRef.value`访问dom
  iptRef.value.focus()
}
</script>

<template>
  <div>
    <!-- 2. 绑定到标签ref属性上 -->
    <input ref="iptRef">
    <br>
    <button @click="clickFn">操作DOM</button>
  </div>
</template>

ref操作组件-defineExpose

组件上使用 ref属性关联响应式数据,获取组件实例

步骤:

  1. 准备父组件、子组件

  2. 父组件内:

    1. 创建ref
    2. 绑定ref到子组件标签上
    3. 通过ref.value访问子组件实例
  3. 子组件内, 调用defineExpose() 💥无需导入,暴露数据和方法

解释:

  • 使用 <script setup> 的组件是默认关闭 的,父组件拿不到子组件的数据和函数。
  • 需要配合 defineExpose 向外暴露数据,暴露的响应式数据会自动解除响应式。

代码:

  1. 准备父组件、子组件(无需注册,直接导入后使用)

components/Child.vue

xml 复制代码
<script setup>
import { ref } from 'vue'

const count = ref(0)
const hello = () => {
  alert("点我干啥")
}
</script>

<template>
  <h3>我是Child组件</h3>
</template>

App.vue

xml 复制代码
<script setup>
// 🔔setup语法中,无需注册组件,直接使用即可
import Child from './components/Child.vue'

const fn = () => {
  
}
</script>

<template>
  <Child />
	<button @click="fn">点我获取子组件内数据和方法</button>
</template>
  1. 父组件内:

    1. 创建ref
    2. 绑定ref到子组件标签上
    3. 通过ref.value访问子组件实例

components/Child.vue

xml 复制代码
<script setup>
import Child from './components/Child.vue'

+ import { ref } from 'vue';
	
// 2.1. 创建ref
+ const childRef = ref()
	const fn = () => {
  	// 2.3. 通过ref.value访问子组件实例
+  	console.log('childRef.value  ----->  ', childRef.value.count);
	}
	
</script>

<template>
  <Child
		// 2.2. 绑定ref到子组件标签上
+  	ref="childRef"
  />
  <button @click="fn">点我获取子组件内数据和方法</button>
</template>
  1. 子组件内,调用definexpose(),暴露数据和方法
xml 复制代码
<script setup>
import { ref } from 'vue'

const count = ref(0)
const hello = () => {
  alert("点我干啥")
}

// 3. 调用`definExpose()`,暴露数据和方法
+  defineExpose({count, hello})
</script>

<template>
  <h3>我是Child组件</h3>
</template>

总结:

  • defineExpose作用:子组件,暴露数据和方法,给实例对象

  • 语法:defineExpose({属性名 , 方法名})

  • 注意:

    • define开头的函数,无需导入

父传子-defineProps函数

目标:能够实现组件通讯中的父传子组件通讯

步骤:

  1. 父组件,声明数据
  2. 父组件,传递数据给子组件
  3. 子组件通过 defineProps 接收props
  4. 子组件渲染父组件传递的数据

静态结构:直接复制

App.vue

xml 复制代码
<script setup>
import { ref } from 'vue'
import MyChild from './components/MyChild.vue'

const money = ref(100)
const car = ref('玛莎拉蒂')
</script>

<template>
  <div>
    <h1>我是父组件</h1>
    <div>金钱:{{ money }}</div>
    <div>车辆:{{ car }}</div>
    <hr />
    <MyChild :money="money" :car="car" />
  </div>
</template>

MyChild.vue

xml 复制代码
<script setup>
</script>

<template>
  <div>
    <h3>我是子组件</h3>
    <div>金钱:{{ money }} <br> 跑车:{{ car }}</div>
    <button>吞金兽想花钱</button>
  </div>
</template>

代码:

xml 复制代码
<script setup>

// defineProps: 接收父组件传递的数据
+ // const props = defineProps(["money", "car"])

+ const props = defineProps({
+   money: Number,
+   car: String,
+ })

</script>

<template>
  <div>
    <h3>我是子组件</h3>
    <div>金钱:{{ money }} <br> 跑车:{{ car }}</div>
    <button>吞金兽想花钱</button>
  </div>
</template>

注意:

  • template中获取props属性,用法与vue2相同

  • script 中也获取 props 属性,

    • vue2中,通过this.属性名
    • vue3中,通过defineProps函数的返回值.属性名

子传父-defineEmits函数

目标:能够实现组件通讯中的子传父组件通讯

步骤:

  1. 子组件通过 defineEmits获取 emit 函数(因为没有this)
  2. 子组件通过 emit 触发事件,并且传递数据
  3. 父组件,监听自定义事件

语法:

  1. const emit = defineEmits(["自定义事件名1", "自定义事件名2"])
  2. emit("自定义事件名", 值)

代码:

MyChild.vue

xml 复制代码
<script setup>
// ... 省略其它代码

// 1.调用defineEmits函数,参数是事件名显性声明事件名称
const emit = defineEmits(['changeMoney'])

</script>

PrarentCom.vue

ini 复制代码
// 3.父组件,监听自定义事件
<MyChild :money="money" :car="car" @changeMoney="changeMoney" />

总结:

  • defineEmits 获取 emit 函数,且组件需要触发的事件需要显性声明出来

跨级组件通讯provide与inject函数

通过provide和inject函数可以简便的实现跨级组件通讯

接下来我们通过一个小案例,运用一下provide和inject函数

落地代码:

  • 祖先组件:App.vue
xml 复制代码
<script setup>
import { provide, ref } from 'vue';
import ParentCom from './ParentCom.vue';

// 1. app组件数据传递给child
const count = ref(0);
provide('count', count);

// 2. app组件函数传递给child,调用的时候可以回传数据
const updateCount = (num) => {
  count.value += num;
};
provide('updateCount', updateCount);
</script>

<template>
  <div
    class="app-page"
    style="border: 10px solid #ccc; padding: 50px; width: 600px"
  >
    app 组件 {{ count }} updateCount
    <ParentCom />
  </div>
</template>
  • 父级组件:ParentCom.vue
xml 复制代码
<script setup>
import ChildCom from './ChildCom.vue';
</script>

<template>
  <div class="parent-page" style="padding: 50px">
    parent 组件
    <hr />
    <ChildCom />
  </div>
</template>
  • 子级组件:ChildCom.vue
xml 复制代码
<script setup>
import { inject } from 'vue';
  
const count = inject('count');
const updateCount = inject('updateCount');
</script>

<template>
  <div class="child-page" style="padding: 50px; border: 10px solid #ccc">
    child 组件 {{ count }} <button @click="updateCount(100)">修改count</button>
  </div>
</template>

总结:

  • provide和inject是解决跨级组件通讯的方案

    • provide 提供后代组件需要依赖的数据或函数
    • inject 注入(获取)provide提供的数据或函数
  • 官方术语:依赖注入

    • App是后代组件依赖的数据和函数的提供者,Child是注入(获取)了App提供的依赖

保持响应式-toRefs函数

掌握:在使用reactive创建的响应式数据被展开或解构的时候使用toRefs保持响应式

大致步骤:

  • 解构响应式数据,踩坑
  • 使用 toRefs 处理响应式数据,爬坑
  • toRefs 函数的作用,与使用场景

落地代码:

  • 基础案例
xml 复制代码
<script setup>
import { ref } from "vue";
const user = ref({ name: "tom", age: 18 });
</script>

<template>
  <div>
    <p>姓名:{{ user.name }}</p>
    <p>年龄:{{ user.age }} <button @click="user.age++">一年又一年</button></p>
  </div>
</template>
  • 使用响应式数据,踩坑
xml 复制代码
<script setup>
import { ref } from "vue";
let user = ref({ name: "tom", age: 18 })
// 解构ref或reactive,会导致响应式丢失
const { name, age } = user.value
</script>

<template>
  <div>
    <p>姓名:{{ name }}</p>
    <p>年龄:{{ age }} <button @click="age++">一年又一年</button></p>
  </div>
</template>
  • 使用 toRefs 处理响应式数据,爬坑
csharp 复制代码
import { ref, toRefs } from "vue";
const user = ref({ name: "tom", age: 18 });
const { name, age } = toRefs(user)

toRefs 函数的作用,与使用场景

  • 作用:把对象中的每一个属性做一次包装成为响应式数据
  • 解构响应式数据的时候使用

总结:

  • 当去解构响应式对象,使用 toRefs 保持响应式

补充-v-model语法糖

掌握:vue3中v-model语法糖原理

回顾:

  • vue2中,v-model 语法糖 完整写法?

    • 原生标签,:value="count"@input="count=$event.target.value"
    • 组件标签,:value="count"@input="..."
  • vue3中,v-model 语法糖 完整写法?

    • 原生标签,:value="count"@input="count=$event.target.value"
    • 组件标签,:modelValue="count"@update:modelValue="..."

为什么变了?

  • vue3 中 组件标签上,可以使用多个v-model 语法糖
xml 复制代码
<com-a v-model="count"></com-a>
<!-- 等价 -->
<com-a :modelValue="count" @update:modelValue="count=$event"></com-a>
xml 复制代码
<com-a v-model="count" v-model:msg="str"></com-a>
<!-- 等价 -->
<com-a :modelValue="count" @update:modelValue="..." :msg="str" @update:msg="..." />

小结:

  • vue3中只需要 v-model 指令可以支持对个数据在父子组件同步,

提问:

  • vue3 中 v-model 语法糖?

    • :modelValue="count"@update:modelValue="count=$event"
  • vue3 中 v-model:xxx 语法糖?

    • :xxx="count"@update:xxx="count=$event"

综合案例

基础准备

初始化代码安装element-plus组件库

  • 克隆代码 https://gitee.com/luckybo0027/vue3-demo-template.git

成功之后:

arduino 复制代码
cd vue3-demo-template
npm i 
npm run dev
  • 模板代码分析

安装 element-plus

css 复制代码
npm i element-plus

使用 element-plus

javascript 复制代码
import { createApp } from 'vue'
import App from './App.vue'

+// element-plus 支持vue3的ui组件库,使用和element-ui一致 
+import ElementUI from 'element-plus'
+import 'element-plus/dist/index.css'

+// use(ElementUI) 使用组件库
+createApp(App).use(ElementUI).mount('#app')
  • 需求说明,使用组合式API实现

    • 列表渲染
    • 删除数据

实现功能

xml 复制代码
<script setup>
import { onMounted, ref } from "vue";
import axios from 'axios'
// 获取列表数据
const list = ref([])
const geList = async () => {
  const res = await axios.get('/list')
  list.value = res.data
}

onMounted(() => {
  geList()
})

// 删除数据
const delRow = async (id) => {
  await axios.delete(`/del?id=${id}`)
  geList()
}
</script>
<template>
  <div class="app">
    <el-table :data="list">
      <el-table-column label="ID" prop="id"></el-table-column>
      <el-table-column label="姓名" prop="name" width="150"></el-table-column>
      <el-table-column label="籍贯" prop="place"></el-table-column>
      <el-table-column label="操作" width="100">
        <template #default="{ row }">
          <el-button type="primary" link @click="delRow(row.id)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<style>
.app {
  width: 980px;
  margin: 100px auto 0;
}
</style>
相关推荐
Qrun7 分钟前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp8 分钟前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.1 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl3 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫5 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友5 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理6 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻7 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
mapbar_front7 小时前
在职场生存中如何做个不好惹的人
前端
牧杉-惊蛰8 小时前
纯flex布局来写瀑布流
前端·javascript·css