关于vue中表单和组件的笔记

14 篇文章 5 订阅

今天内容

  1. 表单
  2. 组件

表单

文本

<input type="text" v-model="message">

多行文本

<textarea v-model="message"></textarea>

单选框

<input type="radio" name="gender" v-model="gender" value=""><input type="radio" name="gender" v-model="gender" value="">

多选框

<input type="checkbox" name="hobby" v-model="hobby" value="游戏">游戏
<input type="checkbox" name="hobby" v-model="hobby" value="睡觉">睡觉
<input type="checkbox" name="hobby" v-model="hobby" checked value="打码">打码

下拉选择框

    <p>
        <select v-model="area">
            <option disabled>请选择</option>
            <option value="重庆">重庆</option>
            <option value="西安">西安</option>
            <option value="北京">北京</option>
        </select>
        <span>{{ area }}</span>
    </p>
    <p>
        <select v-model="area" size="2">
            <option disabled>请选择</option>
            <option value="重庆">重庆</option>
            <option value="西安">西安</option>
            <option value="北京">北京</option>
        </select>
        <span>{{ area }}</span>
    </p>
    <p>
        <select v-model="area" size="3" multiple>
            <option disabled>请选择</option>
            <option value="重庆">重庆</option>
            <option value="西安">西安</option>
            <option value="北京">北京</option>
        </select>
        <span>{{ area }}</span>
    </p>

修饰符

.lazy

<p><input type="text" v-model.lazy="username"></p>
<p>{{ username }}</p>

它是在执行 change 事件或者 blur 事件时才会触发

.number

<p><input type="text" v-model.number="age"></p>
<p>{{ age }}</p>

把输入的值定义为数字

.trim

<p><input type="text" v-model.trim="password"></p>
<p>{{ password }}</p>

注意:修饰符是可以组合使用的。

案例:用户注册

搭建界面
<template>
    <form action="" method="post">
        <table>
            <thead>
            <tr>
                <th colspan="2">用户注册</th>
            </tr>
            </thead>
            <tbody>
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username"></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password"></td>
            </tr>
            <tr>
                <td>性别:</td>
                <td><input type="radio" name="gender" value=""><input type="radio" name="gender" value=""></td>
            </tr>
            <tr>
                <td>邮箱:</td>
                <td><input type="email" name="email"></td>
            </tr>
            <tr>
                <td>密码问题:</td>
                <td><select name="question">
                    <option disabled>请选择</option>
                    <option value="你喜欢的游戏">你喜欢的游戏</option>
                    <option value="你最爱人">你最爱人</option>
                </select></td>
            </tr>
            <tr>
                <td>密码答案:</td>
                <td><select name="question">
                    <option disabled>请选择</option>
                    <option value="LoL">LoL</option>
                    <option value="我自己">我自己</option>
                </select></td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="注册">
                    <input type="reset" value="取消">
                </td>
            </tr>
            </tbody>
        </table>
    </form>
</template>
定义数据
// 定义类型
type User = {
    username: string,
    password: string,
    gender: string,
    email: string,
    question: string,
    answer: string,
}
const user: User = {
    username: '',
    password: '',
    gender: '男',
    email: '',
    question: '',
    answer: ''
}
绑定数据
<template>
    <form action="" method="post">
        <table>
            <thead>
            <tr>
                <th colspan="2">用户注册</th>
            </tr>
            </thead>
            <tbody>
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username" v-model="user.username"></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password" v-model="user.password"></td>
            </tr>
            <tr>
                <td>性别:</td>
                <td><input type="radio" name="gender" value="男" v-model="user.gender"><input type="radio" name="gender" value="女" v-model="user.gender"></td>
            </tr>
            <tr>
                <td>邮箱:</td>
                <td><input type="email" name="email" v-model="user.email"></td>
            </tr>
            <tr>
                <td>密码问题:</td>
                <td><select name="question" v-model="user.question">
                    <option disabled>请选择</option>
                    <option value="你喜欢的游戏">你喜欢的游戏</option>
                    <option value="你最爱人">你最爱人</option>
                </select></td>
            </tr>
            <tr>
                <td>密码答案:</td>
                <td><select name="answer" v-model="user.answer">
                    <option disabled>请选择</option>
                    <option value="LoL">LoL</option>
                    <option value="我自己">我自己</option>
                </select></td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="注册" @click.prevent="register">
                    <input type="reset" value="取消">
                </td>
            </tr>
            </tbody>
        </table>
    </form>
</template>

通过 v-model 指令来把表单元素和数据进行绑定,使用 user.xxx 方式。

绑定事件
<tr>
    <td colspan="2">
        <input type="submit" value="注册" @click.prevent="register">
        <input type="reset" value="取消">
    </td>
</tr>

使用了事件修饰符 .prevent 来阻止表单的默认形为。

const register = () => {
    console.log(user)
}

组件

组件是 Vue 框架的核心,我们前面所学的内容都会在组件中去使用。
一个组件包含三个部分:

  • template : 用于定义视图
  • script:用于定义 TS 脚本,来让组件可用
  • style:编写视图的样式
    这三个部分不是完全必须的,可以根据实际情况来选择基本一到三个

组件基础

基本使用

实际上,在我们通过 vue cli 或者 vite 来创建项目时,会自动给我们添加两个组件:

  • App.vue:它是根组件,我们所有的组件都要通过根组件来使用。
  • HelloWorld.vue:它是一个 hello world 程序,这个组件我们是可以删除

在项目中有一个 components 的目录,这个目录一般用于一些小组件的编写,我们还可以自己定义目录来存放我们组件的组件。
组件是可以复用的。

  1. components 目录下创建一个 Menu.vue 组件
<template>
    <div class="container">
        <ul>
            <li>首页</li>
            <li>新闻</li>
            <li>关于我们</li>
            <li>联系我们</li>
        </ul>
    </div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
  1. 要在根组件 App.vue 中引入
    首先在 App.vue 组件的 script 标签中,通过 import 来把 Menu.vue 组件引入进行
import Menu from './components/Menu.vue'

然后在 App.vue 组件中的 template 标签中使用

<template>
    <Menu></Menu>
</template>

最后就可以启动项目来测试了。

美化组件

我们可以在组件的 style 标签中使用 CSS 来编写样式,也可以使用 SCSS 或者 Less 来编写。
CSS 大家比熟悉,它是不能使用变量,表达式、语句的。而 SCSS 或者 Less 是支持变量、表达式、数组、语句。
所以我们使用 Less 来给大家讲解。
要想使用 Less,我们先安装 Less 依赖和它的加载器依赖
执行如下命令来安装。

npm install less less-loader -D

安装完后,还需要在 style 标签中指定 lang 属性的值为 less

@color: #ffffff;
@bg: #0a53be;
.container {
    width: 100%;
    height: 35px;
    background-color: @bg;

    ul {
        padding: 0;
        margin: 0;
        width: 100%;
        display: flex;
        justify-content: flex-start;
        align-items: center;
        li {
            width: 80px;
            height: 35px;
            list-style: none;
            color: @color;
        }
    }
}

修改根组件

我们需要把项目的入口文件 main.ts 中引入即可。

import { createApp } from 'vue'
import Menu from './components/Menu.vue'

createApp(Menu).mount('#app')

一般来说,我们都不会去修改根组件,而是在根组件中使用别的组件。

组件生命周期

在 Vue3 中有以下几个生命周期方法(钩子)

  • beforeCreate:在组件实例化之后,数据观察和事件/监听设置之前被调用
  • created:在实例创建完成后调用
  • beforeMount:在组件 DOM 实际渲染之前调用。在这一步中,根元素不存在。
  • mounted:在组件第一次渲染之后调用,该元素现在可用,允许直接 DOM 访问
  • beforeUpdate:数据更新之前调用
  • updated:DOM 更新后调用
  • beforeUnmount:在卸载组件实例之前调用,在这个阶段,实例依然可以正常的使用
  • unmounted:卸载组件完成后调用,在这个阶段,所有的事件、计算属性、监听器等都会被移除

演示组件生命周期的使用

import {onBeforeMount, onBeforeUnmount, onBeforeUpdate, onMounted, onUnmounted, onUpdated, ref} from 'vue'

const count = ref<number>(0)
// beforeMount,它是一个钩子函数
onBeforeMount(() => {
    console.log('onBeforeMount....')
})
// onMounted
onMounted(() => {
    console.log('onMounted......');
})
// onBeforeUpdate
onBeforeUpdate(() => {
    console.log('onBeforeUpdate......')
})
// onUpdated
onUpdated(() => {
    console.log('onUpdated......')
})
// onBeforeUnmount
onBeforeUnmount(() => {
    console.log('onBeforeUnmount......')
})
// onUnmounted
onUnmounted(() => {
    console.log('onUnmounted........')
})

组件通信

组件通信就是指组件与组件之间的数据传递。

父传子

  1. 首选一个父组件,我们以 App.vue 来作为父组件。
<template>
    <!--父组件-->
    
</template>

<script setup lang="ts">
</script>
  1. 然后定义一个子组件 Son.vue
<template>
    <h3>子组件</h3>
</template>

<script setup lang="ts">
</script>
  1. 在父组件中引入子组件,并在 template 中使用子组件
<template>
    <!--父组件-->
    <son></son>
</template>

<script setup lang="ts">
import Son from './layout/Son.vue'
</script>
  1. 在子组件的标签上添加一个 title 属性,这个属性就是我们向子组件传递的参数
<template>
    <!--父组件-->
    <son title="hello"></son>
</template>

<script setup lang="ts">
import Son from './layout/Son.vue'
</script>

到目前为止,我们已经完成了父传子的操作。接下来是子组件去接收父组件传递的数据。
5. 在子组件中通过 defineProps API 来接收传递过来的参数。

<template>
    <div>
        <h3>子组件</h3>
        <div>{{ title }}</div>
    </div>
</template>
<script setup lang="ts">
defineProps<{
    title: string
}>()
</script>
默认值

我们希望子组件中接收到的值可以有默认值,如果父组件没有传递参数过来我们就使用默认值,如果有参数传递过来我们就使用传递过来的参数。
也就是说,子组件中的属性是可选的。
要想使用默认值,我们还需要使用别一个 API,它叫 withDefults(),它也是直接使用而无须引入。

type Props = {
    title?: string,
    num?: number,
}
withDefaults(defineProps<Props>(), {
    title: '顶部组件',
    num: 100,
})

withDefaults() 函数有两个参数:第一个参数为接收的属性对象,第二个参数为这些属性的默认值,它也是一个对象。

子传父

子组件定义事件

对于子组件向父组件传递数据,需要做以下几步:
1)在子组件中定义一个事件

<template>
    <div class="menu">
        <button @click="clickTip">派发给父组件</button>
    </div>
</template>

2) 定义要传递的数据

const data = reactive<Array<number>>([1, 2, 3, 4, 5, 6])

3)在子组件中定义派发事件

const emit = defineEmits(['aaaaa'])

定义派发事件需要使用 defineEmits() API,它也是一个可以不用引入就可以直接使用的 API,和 defineProps() 一样。
defineEmits() API,它是一个函数,可以接收一个数组对象,对象中是一些自定义的事件名称。这个函数执行后有一个变更来接收,
通过这个变量(它其实是一个函数)就可以向父组件传值了。
4)在我们指定的事件中来调用 defineEmits() 执行后产生的函数。

const clickTip = () => {
    emit('aaaaa', data)
}

emit (它是一个自己定义的变量),它可以接收两个参数:第一个参数为在派发中指定的事件名称;第二个参数为要传递的数据。

父组件接收数据

父组件要接收子组件传递过来的的数据,需要做以下几步:
1)在要父组件中处定义事件,这个事件的名称必须与子组件派发的事件名称相同

<Menu @aaaaa="getData"></Menu>

2)然后实现事件,来处理获取子组件传递的数据并根据业务需求来处理数据

const dd = reactive<Array<number>>([])

const getData = (d: Array<number>) => {
    dd.push(...d)
}

祖孙传参

在祖组件中使用 provide(key, value) API 来向子组件提供数据

provide('name', '黄飞鸿')

在子组件中使用 const value = inject(key) API 来接收数据

const val = inject('name')

注意:这两个API在使用之前必须先引入。

兄弟传参

实现方式有两种:

  • 兄弟传参需要借助于父组件
  • 使用 Event Bus
借助父组件

首先定义 A.vue 和 B.vue 这两个子组件,它们是平级的,就构成了兄弟组件。
然后在 App.vue 组件中引用。

<template>
    <A></A>
    <B></B>
</template>
<script setup lang="ts">
import A from './borther/A.vue'
import B from './borther/B.vue'
</script>

现在 A.vue 组件要向 B.vue 组件传第一个 name 变量的值。
1)首先在 A.vue 组件中向 App.vue 组件派发一上事件(子传父)

<template>
    <div>A组件</div>
    <button @click="sendDataToApp">向父组件派发事件来传递数据</button>
</template>

<script setup lang="ts">
const name: string = '张三丰'
const emit = defineEmits(['sendData'])
const sendDataToApp = () => {
    emit('sendData', name)
}
</script>

2)然后在 App.vue 组件中通过自定义事件来接收 A.vue 组件会传递的数据

<template>
    <A @sendData="getData"></A>
    <B></B>
</template>
<script setup lang="ts">
import A from './borther/A.vue'
import B from './borther/B.vue'
import {ref} from "vue"
const data = ref<string>('')
const getData = (name: string) => {
    data.value = name
}
</script>

首先通过自定义事件来接收子组件派发的事件,并通过事件来接收数据。
3)父组件 App.vue 向子组件 B.vue 传递参数

<B :name="data"></B>

4)在子组件 B.vue 中接收父组件 App.vue 传递过来的数据

<template>
    <div>B组件 --- {{ name }}</div>
</template>
<script setup lang="ts">
defineProps<{
    name: string
}>()
</script>
使用 Event Bus(了解)

1)定义一个容器,用于收集和执行容器中的事件(在 src 下新建一个 Bus.ts 文件)

type BusClass<T> = {
    emit: (name: T) => void
    on: (name: T, callback: Function) => void
}

// 定义注册中心 Key 的类型
type BusParams = string | number | symbol

// 定义调度中心类型
type List = {
    // 动态属性,使用对象签名的方式来定义
    [key: BusParams]: Array<Function>
}

class Bus<T extends BusParams> implements BusClass<T> {
    // 注册中心
    list: List
    // 调度中心
    constructor() {
        this.list = {}
    }
    // 执行方法
    emit(name: T, ...args: Array<any>) {
        let eventName: Array<Function> = this.list[name]
        eventName.forEach(ev => {
            ev.apply(this, args)
        })
    }
    // 收集方法
    on(name: T, callback: Function) {
        let fn: Array<Function> = this.list[name] || []
        fn.push(callback)
        this.list[name] = fn
    }
}
// 导出
export default new Bus<number>()

2)把这个文件挂载到 Vue 的全局中

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值