vue 从入门到入土---复习 组件基础下

目录

 

props 验证

 计算属性

自定义事件

 组件上的 v-model

任务列表案例

总结


props 验证

1. 什么是 props 验证

指的是 在封装组件时对外界传递过来的 props 数据进行合法性的校验 从而防止数据不合法的问题 

使用数组类型的 props 节点的缺点:无法为每个 prop 指定具体的数据类型

2. 对象类型的 props 节点

使用对象类型的 props 节点,可以对每个 prop 进行数据类型的校验,示意图如下

 3. props 验证

对象类型的 props 节点提供了多种数据验证方案,例如

  • ① 基础的类型检查
  • ② 多个可能的类型
  • ③ 必填项校验
  • ④ 属性默认值
  • ⑤ 自定义验证函数

3.1 基础的类型检查        

可以直接为组件的 prop 属性指定基础的校验类型 从而防止组件的使用者为其绑定错误类型的数据

 3.2 多个可能的类型

如果某个 prop 属性值的类型不唯一,此时可以通过数组的形式,为其指定多个可能的类型

 3.3 必填项校验

如果 组件的某个 prop 属性是必填项 ,必须让组件的使用者为其传递属性的值。此时,可以通过如下的方式将 其设置为必填项:

 3.4 属性默认值

在封装组件时,可以为某个 prop 属性指定默认值。示例代码如下:

 3.5 自定义验证函数

在封装组件时 可以为 prop 属性指定自定义的验证函数从而对 prop 属性的值进行更加精确的控制

 计算属性

1. 什么是计算属性

计算属性 本质上 就是一个 function 函数 ,它可以 实时监听 data 中数据的变化,并 return 一个计算后的新值 , 供组件渲染 DOM 时使用
2. 如何声明计算属性
计算属性需要以 function 函数 的形式声明到组件的 computed 选项 中,示例代码如下:

 注意:计算属性侧重于得到一个计算的结果,因此计算属性中必须有 return 返回值

3. 计算属性的使用注意点        

  • ① 计算属性必须定义在 computed 节点中
  • ② 计算属性必须是一个 function 函数
  • ③ 计算属性必须有返回值
  • ④ 计算属性必须当做普通属性使用

4. 计算属性 vs 方法

相对于方法来说, 计算属性会缓存计算的结果 ,只有计算属性的 依赖项发生变化 时,才会 重新进行运算 。因此 计算属性的性能更好:

 5. 计算属性案例

案例需求,使用计算属性动态计算:
  • ① 已勾选的商品总个数
  • ② 已勾选的商品总价
  • ③ 结算按钮的禁用状态

自定义事件

1.什么是自定义事件

在封装组件时 为了让组件的使用者可以监听到组件内状态的变化 此时需要用到组件的自定义事件

2. 自定义事件的 3 个使用步骤        

在封装组件时:
  • 声明自定义事件
  • 触发自定义事件
在使用组件时:
监听 自定义事件
2.1 声明 自定义事件
开发者为自定义组件封装的 自定义事件 ,必须事先在 emits 节点中声明,示例代码如下:

 2.2 触发自定义事件

emits 节点下声明的自定义事件,可以通过 this.$emit('自定义事件的名称') 方法进行触发

 2.3 监听自定义事件

在调用 this.$emit() 方法触发自定义事件时,可以通过第 2 个参数为自定义事件传参

 组件上的 v-model

1.为什么需要在组件上使用 v-model

v-model 是双向数据绑定指令 当 需要维护组件内外数据的同步 时 可以在组件上使用 v-model 指令
  • 外界数据的变化自动同步到 counter 组件中
  • counter 组件中数据的变化,也会自动同步到外界

 2. 在组件上使用 v-model 的步骤

任务列表案例

1. 案例效果

 2. 用到的知识点

  • ① vite 创建项目
  • ② 组件的封装与注册
  • ③ props
  • ④ 样式绑定
  • ⑤ 计算属性
  • ⑥ 自定义事件
  • ⑦ 组件上的 v-model

 3. 整体实现步骤

1. 初始化项目
  • 1. 在终端运行以下的命令,初始化 vite 项目:
  • 2. 使用 vscode 打开项目,并安装依赖项:
  • 3. 安装 less 语法相关的依赖项:
npm init vite-app todos
npm install
npm i less -D
2. 梳理项目结构
1. 重置 index.css 中的全局样式如下:
:root {
  font-size: 12px;
}

body {
  padding: 8px;
}
2. 重置 App.vue 组件的代码结构如下:
<template>
  <h1>app 根组件</h1>
</template>

<script>
export default {
  name: "MyApp",
  data() {
    return {
      //任务列表数据
      todolist: [
        { id: 1, task: "周一早晨9点开会", done: false },
        { id: 2, task: "周一晚上8点聚餐", done: false },
        { id: 3, task: "准备周三上午的演讲稿", done: true },
      ],
    };
  },
};
</script>

<style lang="less" scoped>
</style>
.
3.删除 components 目录下的 HelloWorld.vue 组件
4.在终端运行以下的命令, npm run dev
3. 封装 todo-list 组件
1. 在 src/components/todo-list/ 目录下新建 TodoList.vue 组件
<template>
  <div></div>
</template>

<script>
export default {
  name: "TodoList",
};
</script>

<style lang="less" scoped>
</style>
2.在 App.vue 组件中导入并注册 TodoList.vue 组件:
// 导入 TodoList 组件
import TodoList from './components/todo-list/TodoList.vue'
export default {
 name: 'MyApp',
 // 注册私有组件
 components: {
 TodoList,
 },
}
3. App.vue template 模板结构中使用注册的 TodoList 组件:
<template>
 <div>
 <h1>App 根组件</h1>
 <hr />
 
 <!-- 使用 todo-list 组件 -->
 <todo-list></todo-list>
 </div>
</template>
3.2 基于 bootstrap 渲染列表组件
1. 将 资料 目录下的 css 文件夹拷贝到 src/assets/ 静态资源目录中。
2. 在 main.js 入口文件中,导入 src/assets/css/bootstrap.css 样式表:
import { createApp } from 'vue'
import App from './App.vue'
// 导入 bootstrap.css 样式表
import './assets/css/bootstrap.css'
import './index.css'
createApp(App).mount('#app')
3. 根据 bootstrap 提供的渲染列表组件的基本效果:
列表组 https://v4.bootcss.com/docs/components/list-group/#with-badges
复选框 https://v4.bootcss.com/docs/components/forms/#checkboxes-and-radios-1
<template>
 <ul class="list-group">
 <li class="list-group-item d-flex justify-content-between
align-items-center">
 <!-- 复选框 -->
 <div class="custom-control custom-checkbox">
 <input type="checkbox" class="custom-control-input"
id="customCheck1" />
 <label class="custom-control-label"
for="customCheck1">Check this custom checkbox</label>
 </div>
 <!-- badge 效果 -->
 <span class="badge badge-success badge-pill">完成</span>
 <span class="badge badge-warning badge-pill">未完成</span>
 </li>
 </ul>
</template> 

3.3 TodoList 声明 props 属性

1. 为了接受外界传递过来的列表数据,需要在 TodoList 组件中声明如下的 props 属性:
export default {
 name: 'TodoList',
   props: {
    list: {
      type: Array,
      required: true,
      default: [],
    },
  },
};
2.在 App 组件中通过 list 属性,将数据传递到 TodoList 组件之中:
<todo-list :list="todolist"></todo-list>
3.4 渲染列表的 DOM 结构
1. 通过 v-for 指令,循环渲染列表的 DOM 结构:
<template>
 <ul class="list-group">
 <li class="list-group-item d-flex justify-content-between
align-items-center" v-for="item in list" :key="item.id">
 <!-- 复选框 -->
 <div class="custom-control custom-checkbox">
 <input type="checkbox" class="custom-control-input"
:id="item.id" />
 <label class="custom-control-label" :for="item.id">{{
item.task }}</label>
 </div>
 <!-- badge 效果 -->
 <span class="badge badge-success badge-pill">完成</span>
 <span class="badge badge-warning badge-pill">未完成</span>
 </li>
 </ul>
</template> 
2. 通过 v-if v-else 指令,按需渲染 badge 效果:
<!-- badge 效果 -->
<span class="badge badge-success badge-pill" v-if="item.done">完成
</span> <span class="badge badge-warning badge-pill" v-else>未完成</span>
3. 通过 v-model 指令,双向绑定任务的完成状态:
<!-- 复选框 -->
<input type="checkbox" class="custom-control-input" :id="item.id"
v-model="item.done" />
<!-- 注意:App 父组件通过 props 传递过来的 list 是“引用类型”的数
据, -->
<!-- 这里 v-model 双向绑定的结果是:用户的操作修改的是 App 组件中数
据的状态 -->
4. 通过 v-bind 属性绑定,动态切换元素的 class 类名:
<label class="custom-control-label" :class="item.done ? 'delete' :
''" :for="item.id">{{ item.task }}</label>
TodoList 组件中声明如下的样式,美化当前组件的 UI 结构:
// 为列表设置固定宽度
.list-group {
 width: 400px; }
// 删除效果
.delete {
 text-decoration: line-through; }

4. 封装 todo-input 组件 

4.1 创建并注册 TodoInput 组件
1. 在 src/components/todo-input/ 目录下新建 TodoInput.vue 组件:
<template>
 <div>TodoInput 组件</div>
</template> <script>
export default {
 name: 'TodoInput', }
</script> <style lang="less" scoped></style> 
2. 在 App.vue 组件中导入并注册 TodoInput.vue 组件:
// 导入 TodoList 组件
import TodoList from './components/todo-list/TodoList.vue'
// 导入 TodoInput 组件
import TodoInput from './components/todo-input/TodoInput.vue'
export default {
 name: 'MyApp',
 // 注册私有组件
 components: {
 TodoList,
 TodoInput,
 },
} 
3. App.vue template 模板结构中使用注册的 TodoInput 组件:
<template>
 <div>
 <h1>App 根组件</h1>
 <hr />
 <!-- 使用 TodoInput 组件 -->
 <todo-input></todo-input>
 <!-- 使用 TodoList 组件 -->
 <todo-list :list="todolist" class="mt-2"></todo-list>
 </div>
</template> 
4.2 基于 bootstrap 渲染组件结构
1. 根据 bootstrap 提供的 inline-forms渲染 TodoInput 组件的基本结构。
https://v4.bootcss.com/docs/components/forms/#in line-forms
<template>
  <!-- form 表单 -->
  <form class="form-inline">
    <div class="input-group mb-2 mr-sm-2">
      <!-- 输入框的前缀 -->
      <div class="input-group-prepend">
        <div class="input-group-text">任务</div>
      </div>
      <!-- 文本输入框 -->
      <input
        type="text"
        class="form-control"
        placeholder="请填写任
务信息"
        style="width: 356px"
      />
    </div>

    <!-- 添加按钮 -->
    <button type="submit" class="btn btn-primary mb-2">添加新任务</button>
  </form>
</template> 
4.3 通过自定义事件向外传递数据
1. 在 TodoList 组件的 data 中声明如下的数据:
data() {
 return {
 // 新任务的名称
 taskname: '',
 }
} 
2. 为 input 输入框进行 v-model 的双向数据绑定:
<input type="text" class="form-control" placeholder="请填写任务信
息" style="width: 356px" v-model.trim="taskname" />
3. 监听 form 表单的 submit 事件,阻止默认提交行为并指定事件处理函数:
<form class="form-inline" @submit.prevent="onFormSubmit"></form>
4. 在 methods 中声明 onFormSubmit 事件处理函数如下:
methods: {
 // 表单提交的事件处理函数
 onFormSubmit() {
 // 1. 判断任务名称是否为空
 if (!this.taskname) return alert('任务名称不能为空!')
 // 2. 触发自定义的 add 事件,并向外界传递数据
 // 3. 清空文本框
 },
}
5. 声明自定义事件如下:
export default {
 name: 'TodoInput',
 // 声明自定义事件
 emits: ['add'],
}
6. 进一步完善 onFormSubmit 事件处理函数如下:
methods: {
 // 表单提交的事件处理函数
 onFormSubmit() {
 // 1. 判断任务名称是否为空
 if (!this.taskname) return alert('任务名称不能为空!')
 // 2. 触发自定义的 add 事件,并向外界传递数据
 this.$emit('add', this.taskname)
 // 3. 清空文本框
 this.taskname = ''
 },
},
4.4 实现添加任务的功能
1. App.vue 组件中监听 TodoInput 组件自定义的 add 事件
<!-- 使用 TodoInput 组件 -->
<!-- 监听 TodoInput 的 add 自定义事件 -->
<todo-input @add="onAddNewTask"></todo-input>
2. 在 App.vue 组件的 data 中声明 nextId 来模拟 id 自增 +1 的操作:
data() {
 return {
 // 任务列表的数据
 todolist: [
 { id: 1, task: '周一早晨9点开会', done: false },
 { id: 2, task: '周一晚上8点聚餐', done: false },
 { id: 3, task: '准备周三上午的演讲稿', done: true },
 ],
 // 下一个可用的 Id 值
 nextId: 4,
 }
},
3. 在 App.vue 组件的 methods 中声明 onAddNewTask 事件处理函数如下:
methods: {
 // TodoInput 组件 add 事件的处理函数
 onAddNewTask(taskname) {
 // 1. 向任务列表中新增任务信息
 this.todolist.push({
 id: this.nextId,
 task: taskname,
 done: false, // 完成状态默认为 false
 })
 
 // 2. 让 nextId 自增+1
 this.nextId++
 },
},
5. 封装 todo-button 组件
5.1 创建并注册 TodoButton 组件
1. 在 src/components/todo-button/ 目录下新建 TodoButton.vue 组件:
<template>
 <div>TodoButton 组件</div>
</template> <script>
export default {
 name: 'TodoButton', }
</script> <style lang="less" scoped></style>
2.在 App.vue 组件中导入并注册 TodoButton.vue 组件:
// 导入 TodoList 组件
import TodoList from './components/todo-list/TodoList.vue'
// 导入 TodoInput 组件
import TodoInput from './components/todo-input/TodoInput.vue'
// 导入 TodoButton 组件
import TodoButton from './components/todo-button/TodoButton.vue'
export default {
 name: 'MyApp',
 // 注册私有组件
 components: {
 TodoList,
 TodoInput,
 TodoButton
 },
}
5.2 基于 bootstrap 渲染组件结构
1. 根据 bootstrap 提供的 Button group渲染 Todobutton 组件的基本结构。
https://v4.bootcss.com/docs/components/button-group/
2. TodoButton 组件中渲染如下的 DOM 结构
<template>
  <div class="button-container mt-3">
    <div class="btn-group">
      <button type="button" class="btn btn-primary">全部</button>
      <button type="button" class="btn btn-secondary">已完成</button>
      <button type="button" class="btn btn-secondary">未完成</button>
    </div>
  </div>
</template>
3. 并通过 button-container 类名美化组件的样式:
.button-container {
 // 添加固定宽度
 width: 400px;
 // 文本居中效果
 text-align: center; }
5.3 通过 props 指定默认激活的按钮
TodoButton 组件中声明如下的 props ,用来指定默认激活的按钮的索引:
 name: 'TodoButton',
 props: {
 // 激活项的索引值
 active: {
 type: Number,
 required: true,
 // 默认激活索引值为 0 的按钮(全部:0,已完成:1,未完成:2)
 default: 0,
 },
 },
}
2. 通过 动态绑定 class 类名 的方式控制按钮的激活状态:
<template>
 <div class="button-container mt-3">
 <div class="btn-group">
 <button type="button" class="btn" :class="active === 0 ?
'btn-primary' : 'btn-secondary'">全部</button>
 <button type="button" class="btn" :class="active === 1 ?
'btn-primary' : 'btn-secondary'">已完成</button>
 <button type="button" class="btn" :class="active === 2 ?
'btn-primary' : 'btn-secondary'">未完成</button>
 </div>
 </div>
</template>
3. App 组件中声明 默认激活项的索引 ,并通过 属性绑定 的方式传递给 TodoButton 组 件
data() {
 return {
 // 激活的按钮的索引
 activeBtnIndex: 0
 }
}
<!-- 使用 TodoButton 组件 -->
<todo-button :active="activeBtnIndex"></todo-button> 1
5.4 通过 v-model 更新激活项的索引
需求分析:
-> 通过 props 传递了激活项的索引( active
-> 需要更新父组件中激活项的索引
这种场景下适合 在组件上使用 v-model 指令 ,维护 组件内外数据的同步
1. TodoButton 组件中的三个按钮分别绑定 click 事件处理函数如下:
<button type="button" class="btn" :class="active === 0 ? 'btnprimary' : 'btn-secondary'" @click="onBtnClick(0)">
 全部
</button> <button type="button" class="btn" :class="active === 1 ? 'btnprimary' : 'btn-secondary'" @click="onBtnClick(1)">
 已完成
</button> <button type="button" class="btn" :class="active === 2 ? 'btnprimary' : 'btn-secondary'" @click="onBtnClick(2)">
 未完成
</button> 
2. TodoButton 组件中声明如下的自定义事件,用来更新父组件通过 v-model 指令传递过来
props 数据:
export default {
 name: 'TodoButton',
 // 声明和 v-model 相关的自定义事件
 emits: ['update:active'],
 props: {
 // 激活项的索引值
 active: {
 type: Number,
 required: true,
 default: 0,
 },
 },
}
3.在 TodoButton 组件的 methods 节点中声明 onBtnClick 事件处理函数如下:
methods: {
 // 按钮的点击事件处理函数
 onBtnClick(index) {
 // 1. 如果当前点击的按钮的索引值,等于 props 传递过来的索引值,
则没必要触发 update:active 自定义事件
 if (index === this.active) return
 // 2. 通过 this.$emit() 方法触发自定义事件
 this.$emit('update:active', index)
 },
},
12345678
5.5 通过计算属性动态切换列表的数据
需求分析:
点击不同的按钮,切换显示不同的列表数据。此时可以根据当前激活按钮的索引,动态计算出要显 示的列表数据并返回即可!
1. 在 App 根组件中声明如下的计算属性:
computed: {
 // 根据激活按钮的索引值,动态计算要展示的列表数据
 tasklist() {
 // 对“源数据”进行 switch...case 的匹配,并返回“计算之后的结果”
 switch (this.activeBtnIndex) {
 case 0: // 全部
 return this.todolist
 case 1: // 已完成
 return this.todolist.filter(x => x.done)
 case 2: // 未完成
 return this.todolist.filter(x => !x.done)
 }
 },
},
2. 在 App 根组件的 DOM 结构中,将 TodoList 组件的 :list="todolist" 修改为:
<!-- 使用 TodoList 组件 -->
<todo-list :list="tasklist" class="mt-2"></todo-list> 1

总结

① 能够知道如何对 props 进行验证

数组格式、对象格式

typedefaultrequired、validator

② 能够知道如何使用计算属性

 computed 节点、必须 return 一个结果、缓存计算结果

③ 能够知道如何为组件绑定自定义事件

 v-on 绑定自定义事件、emits$emit()

④ 能够知道如何在组件上使用 v-model

应用场景:实现组件内外的数据同步

v-model:props名称、emits、$emit('update:props名称')

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值