Vue3.2 组件实例练习
版本说明
node v14.17.0
vite v2.6.4
yarn v1.22.11
typescript v4.4.3
vue v3.2.16
创建项目
使用vite
yarn create vite TestPro --template vue-ts
安装依赖
cd TestPro
yarn
启动项目
yarn dev
安装依赖完成的package.json
{
"name": "testpro",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"serve": "vite preview"
},
"dependencies": {
"vue": "^3.2.16"
},
"devDependencies": {
"@vitejs/plugin-vue": "^1.9.3",
"typescript": "^4.4.3",
"vite": "^2.6.4",
"vue-tsc": "^0.3.0"
}
}
新建组件
MyInput.vue
<script lang="ts" setup>
import { computed, onMounted, ref } from "@vue/runtime-core";
// 接收绑定的参数
let props = defineProps({
name: {
type: String,
required: true,
},
type: {
type: String,
validator(value: string): boolean { // 绑定自定义的属性验证
return ["password", ""].includes(value);
},
},
validator: {
type: RegExp, // 验证字符串是正则类型
},
validator_success: {
type: String,
},
validator_error: {
type: String,
},
});
// 接收父组件的方法
let emit = defineEmits(["update:name"]);
// 绑定 input 事件
let OnInput = (ev: Event): void => {
// 执行父组件的方法
emit("update:name", (ev.target as any).value); // 此处为了防止ts报类型错误
};
// 输入框的样式 如果是密码框需要
let inputtype = ref("text");
onMounted(() => {
if (props.type == "password") {
inputtype.value = "password";
}
});
// 验证信息显示
let tip = computed(() => {
return props.name && props.validator ? true : false;
});
// 验证结果显示的颜色
let tipcolor = computed(() => {
// 验证结果
if (props.validator && props.validator.test(props.name)) {
// 有验证且验证成功
return "green";
} else {
return "red";
}
});
// 验证信息
let tipmsg = computed(() => {
if (props.validator && props.validator.test(props.name)) {
// 有验证且验证成功
return "√ " + (props.validator_success || "验证成功!");
} else {
return "× " + (props.validator_error || "验证失败!");
}
});
</script>
<template>
<div class="container">
<div class="input-data">
<input :type="inputtype" required :value="name" @input="OnInput" />
<!-- @input可以使用下面的这个,但是会报ts类型错误,虽然并不影响显示结果 -->
<!-- @input="$emit('update:name', $event.target.value)" -->
<label>
<slot name="default"> name </slot>
</label>
<div class="line"></div>
<transition>
<div class="tips" v-if="tip">{{ tipmsg }}</div>
</transition>
</div>
</div>
</template>
<style scoped>
.container {
width: 450px;
background-color: #fff;
padding: 20px;
}
.container .input-data {
width: 100%;
height: 40px;
position: relative;
}
.container .input-data input {
position: absolute;
bottom: 0;
left: 0;
height: 100%;
width: 100%;
padding-left: 10px;
border: none;
outline: none;
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 17px;
}
.container .input-data input:focus {
color: #4158d0;
}
.container .input-data input:focus ~ label {
color: #333;
}
.container .input-data input:focus ~ label,
.container .input-data input:valid ~ label {
transform: translateY(-25px);
}
.container .input-data label {
position: absolute;
bottom: 10px;
left: 10px;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
pointer-events: none;
transition: all 0.3s ease;
font-size: 20px;
color: rgb(160, 157, 157, 0.6);
}
.container .input-data .line,
.container .input-data .line:before {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 1.5px;
}
.container .input-data .line {
background-color: gray;
}
.container .input-data .line:before {
content: "";
background-color: #4158d0;
transform: scaleX(0);
transition: transform 0.4s ease;
}
.container .input-data input:focus ~ .line:before {
transform: scaleX(1);
}
.container .input-data .tips {
position: absolute;
width: 100%;
height: 15px;
bottom: -15px;
font-size: 9px;
left: 10px;
text-align: left;
color: v-bind(tipcolor); /* vue 3.2 可以为css绑定参数 */
transition: all 0.3s ease;
}
</style>
在App.vue中注册使用
<script setup lang="ts">
import { ref } from "vue";
import MyInput from "./components/MyInput.vue";
let username = ref("");
let password = ref("");
let validator_username = /[a-zA-Z][a-zA-Z0-9]{8,20}/
</script>
<template>
<MyInput v-model:name="username" :validator=validator_username> username </MyInput>
<MyInput v-model:name="password" type="password"> password </MyInput>
</template>
|