在我们项目的上一个阶段中,我们通过设置项目样板,集成必要的库以及编写Login.vue
,Register.vue
和Dashboard.vue
(例如Register.vue
和Dashboard.vue
)来成功建立了基础方面。我们还配置了路由以确保整个应用程序中的平稳导航。
如果您达到了这一点,恭喜这项出色的成就!现在,我们即将深入研究可重复使用的组件的领域,这是建立模块化和可维护应用的关键一步。
要提供我们当前文件夹结构的快照,您可以参考下图:
在/src/components
目录中,让我们根据其功能将组件组织到不同的文件夹中。您将创建四个主要文件夹:/auth
,/common
,/dashboard
和/utility
。
虽然可以根据您的喜好对名称进行调整,但该结构促进了一种以功能为中心的方法。例如,与身份验证关联的组件将位于/src/auth
文件夹中,并且类似地用于其他功能。
但是,/src/common
文件夹将是我们制作可重复使用组件的起点。
创建一个“ Navbar”组件:
/src/components/common/Navbar.vue
<template>
<header class="flex justify-between items-center bg-primary p-5">
<h1 class="font-popins text-4xl text-[#fff]"> {{ returnResponsiveTitle }}</h1>
<div class="flex items-center">
<nav v-if="!isMobile">
<ul class="flex ">
<li
class="p-4 w-[120px] text-center font-popins rounded-2xl"
v-for="(url , index) in urlDatas " :key="index">
<router-link class="text-[#FFFFFF] " :to="{name: url.url}">{{ url.name }}</router-link>
</li>
</ul>
</nav>
<div class="flex items-center justify-center bg-[#fff] w-[50px] h-[50px] rounded-full">
<h1 class="text-2xl font-popins font-bold">MA</h1>
</div>
<div v-if="isMobile" class="flex items-center justify-center p-2 rounded-sm">
<font-awesome-icon
@click="toggleNav"
class="text-4xl text-[#ffff] cursor-pointer"
:icon="['fas', `${showNav ? 'times': 'hamburger'}`]"/>
</div>
</div>
</header>
<!-- show on mobile -->
<div class="bg-primary" v-if="isMobile">
<div class="flex flex-col" v-if="showNav">
<nav>
<ul class="flex flex-col">
<li
class="p-4 w-[120px] font-popins rounded-2xl"
v-for="(url , index) in urlDatas " :key="index">
<router-link class="text-[#FFFFFF] " :to="{name: url.url}">{{ url.name }}</router-link>
</li>
</ul>
</nav>
</div>
</div>
</template>
<script>
export default {
name:'NavBar',
data(){
return {
urlDatas: [
{
url: 'login',
name: 'Login',
},
{
url: 'register',
name: 'Register',
},
{
url: 'dashboard',
name: 'Dashboard',
}
],
isMobile: false,
showNav: false,
}
},
mounted(){
this.checkScreenSize();
addEventListener('resize' , this.checkScreenSize )
},
methods: {
checkScreenSize() {
this.isMobile = window.innerWidth <= '768'
},
toggleNav(){
this.showNav = !this.showNav
}
},
computed: {
returnResponsiveTitle() {
if(this.isMobile){
return 'Vma'
}
return 'VueMadeEasy'
}
}
}
</script>
此“ Navbar”组件是一个响应式导航栏,可根据屏幕尺寸调整其布局。它具有一个动态标题,该标题在移动设备和“ Vuemadeeasy”的“ VMA”之间更改。导航项目显示为链接,并且在移动设备上显示一个切换按钮以展开或折叠导航菜单。
接下来,您将注册并使用app.vue文件中的navbar组件。
/src/App.vue
<template>
<NavBar />
<RouterView />
</template>
<script>
import NavBar from './components/common/NavBar.vue'
export default {
components: {
NavBar
}
}
</script>
通过在App.Vue中集成“ Navbar”组件,您已经在应用程序上建立了一个一致的导航元素。这种模块化方法简化了开发并确保组件的可重复使用性。
现在,让我们继续使用/utility
文件夹。在这里,您将创建组件,这些组件用作应用程序多个部分中使用的构件。这些组件在保持一致性的同时显着增强了控制和灵活性。
考虑更改应用程序中输入字段的焦点颜色。您永远不想在任何地方开始这样做。在这种情况下,您只需将所有必要的更改应用于/utility
文件夹中的组件即可。瞧!更改将反映在使用组件的应用程序的所有领域。
创建实用程序组件:
/src/components/utility/BaseButton.vue
<template>
<div class="div">
<label
class="size-2xl"
:for="id">{{ label }}</label>
<input
:id="id"
:class="[isFocused && 'focused']"
class="p-2 border-2 border-[#eee] w-full rounded-xl"
:type="text"
:placeholder="placeHolder"
@focus="isFocused = true"
@blur="isFocused = false"
@input="handleText"
:value="value"
:aria-label="label"
:aria-describedby="`${id}-description`"
>
<div
v-if="error"
class="h-[10px] mt-1">
<span class="text-[red]">{{ msg }}</span>
</div>
</div>
</template>
<script>
export default {
name:'BaseInput',
props: {
id: String,
label:String,
text: String,
placeHolder: String,
value: [String , Number],
error: {
type: Boolean,
default: false,
},
msg: {
type: String,
msg: '',
}
},
data(){
return {
isFocused: false,
}
},
methods: {
handleText(e){
this.$emit('update:modelValue', e.target.value )
}
}
}
</script>
<style scoped>
.focused{
outline: 2px solid #414066;
box-shadow: 0px 2px 5px rgba(0, 0, 0, .3);
}
</style>
在脚本部分中,该组件被命名为“ baseinput”,并采用包括ID,标签,占位符,值,错误和MSG在内的道具。它利用ISFOCEDE数据属性来监视输入焦点,而Handletext方法触发了update:modelValue
事件,在更改输入值时会发出输入值。
/src/components/utility/BaseModal.vue
<template>
<div class="flex items-center justify-center h-[100%] bg-[#242222b7] w-full">
<div class="bg-[#fff] w-1/5 h-2/5 flex flex-col drop-shadow-sm rounded-lg">
<span class="flex items-center justify-end p-4 right-0">
<font-awesome-icon
@click="handleClose"
class="mb-5 text-2xl c-tst cursor-pointer" :icon="['fa', 'times']" />
</span>
<div class="flex flex-col items-center justify-center w-full">
<font-awesome-icon class="text-7xl mb-5 text-[green]" :icon="['fa', 'circle-check']" />
<h1 class="text-4xl font-popins font-bold">Success</h1>
</div>
</div>
</div>
</template>
<script>
export default {
name:'BaseModal',
methods: {
handleClose(){
this.$emit('close')
}
}
}
</script>
接下来,使用暗半透明背景定义模态组件。在模态内部,有一个带有白色背景的容器,显示了一个检查标记图标和成功消息。由时图表示的关闭按钮位于右上角。
在脚本部分中,名为“ basemodal”的组件包括一个名为“ handleclose”的方法,该方法在触发时发出'Close'事件。
此组件似乎是一种成功模式,它显示了Checkmark图标以及成功消息和关闭按钮。单击时,“关闭”按钮会发出自定义的“关闭”事件,允许父组件处理模态闭合行为。
/src/components/utility/BaseButton
<template>
<button
:class="['p-3 text-center w-full rounded-4xl', variantClass ]"
:disabled="disabled"
:aria-disabled="disabled"
@click="handleClick"
type="submit"
>
{{ label }}
</button>
</template>
<script>
export default {
name:'BaseButton',
props: {
label: String,
variant: {
type: String,
default: 'primary',
},
disabled: Boolean,
},
computed: {
variantClass(){
if(this.disabled){
return `variant-${this.variant}-disabled`;
}
return `variant-${this.variant}`;
}
},
methods: {
handleClick() {
this.$emit('clk');
},
}
}
</script>
<style>
/* variant style */
.variant-primary {
background-color: #414066;
color: #fff;
}
.variant-primary-disabled {
background-color: #414066c3;
cursor: not-allowed;
}
.variant-secondary {
background-color: #4C6640;
color: #fff;
}
.variant-secondary-disabled {
background-color: #4c6640b4;
cursor: not-allowed;
}
</style>
接下来,为“ basebutton”创建.VUE文件。根据文件中的变体和禁用状态定义一个带有动态类的按钮。按钮的单击事件触发了发射“ clk”事件的处理方法。
在脚本部分中,名为“ basebutton”的组件接受包括标签,变体和禁用的道具。计算的属性“ VariantClass”基于变体和残疾状态动态生成类名称。 HandleClick方法发出了“ CLK”事件。
样式部分包括针对按钮不同变体的CSS规则,根据变体和残疾状态调整背景颜色和光标。
/src/components/utility/BaseToast.vue
<template>
<div v-if="show" class="p-3 flex border-t-4 border-t-[#525252] justify-between items-center bg-[#fee2e2] h-[70px]">
<h2 class="text-[#e74e3c] text-sm">Oops! {{ msg }}</h2>
<div class="p-3">
<font-awesome-icon
class="text-4xl text-[#e74e3c]"
:icon="['fas', 'exclamation']" />
</div>
</div>
</template>
<script>
export default {
name:'AppToast',
props: {
variant: {
type: String,
default: 'default',
},
show: Boolean,
msg: String,
},
}
</script>
A Toast组件是根据“表演”道具的条件渲染而创建的。烤面包在彩色条中显示消息和图标。该消息是用“糟糕!”动态生成的。字首。条形和图标的颜色由“变体”支撑
确定在脚本部分中,名为“ apptoast”的组件接受包括“变体”,“ show”和“ msg”的道具。 “变体”支柱定义了配色方案,“显示”控制是否显示了吐司,而“ msg”保存了消息内容。
此组件旨在显示带有可自定义消息和颜色的通知敬酒,为用户提供了各种消息或警报的可视化指示器。
现在您已经创建了所需的所有实用程序组件,让我们使用它们来创建您的“登录”和“注册”屏幕。
/src/components/auth/AuthLogin.vue
<template>
<auth-wrapper class="m-auto mt-5">
<h1 class="text-primary pt-5 pb-5 font-bold text-2xl font-popins">Login</h1>
<app-input
:id = "'username'"
:label = "'Username :'"
:value = "userName"
:error = "user.error"
:text = "'text'"
:placeHolder="'Enter your username'"
:msg = "user.msg"
v-model="userName"
/>
<app-input
class="mt-7"
:id = "password"
:label = "'Password :'"
:text = "'password'"
:placeHolder="'Enter your password'"
:value = "password"
:error = "user.error"
:msg = "user.msg"
v-model="userName"
/>
<app-button
class="mt-7 mb-3"
:disabled="false"
:label="'Sign In'"
:variant="'primary'"
@clk="handleSubmit"
/>
<p class="mb-10 text-right">Already have an account?
<router-link
class="text-primary"
:to="{name:'register'}">sign up
</router-link></p>
</auth-wrapper>
</template>
<script>
import AppButton from '../utility/BaseButton.vue';
import AppInput from '../utility/BaseInput.vue';
import AuthWrapper from './part/AuthWrapper.vue';
export default {
name:'AuthLogin',
components: {
AuthWrapper,
AppInput,
AppButton,
},
data(){
return {
userName: '',
password: '',
user: {
error: false,
msg: 'invalid input field!',
}
}
},
methods: {
handleSubmit(){
console.log('hello')
}
}
}
</script>
接下来,您必须在登录视图中使用此组件
src/views/Login.vue
<template>
<auth-login/>
</template>
<script>
import AuthLogin from '../components/auth/AuthLogin.vue'
export default {
name:'LoginView',
components: {
AuthLogin
},
}
</script>
此代码创建一个称为“ loginview”的视图组件,该组件使用“ authlogin”组件呈现用户登录表单。 “ authlogin”组件被导入并注册为儿童组件以可重复使用和模块化。
/src/components/auth/AuthSignup.vue
<template>
<auth-wrapper class="m-auto mt-5">
<h1 class="text-primary pt-5 pb-5 font-bold text-2xl font-popins">Register</h1>
<app-input
:id = "'username'"
:label = "'Username :'"
:value = "userName"
:error = "user.error"
:text = "'text'"
:placeHolder="'Enter your username'"
:msg = "user.msg"
v-model="userName"
/>
<app-input
class="mt-7"
:id = "'email'"
:label = "'Email :'"
:value = "email"
:error = "user.error"
:text = "'email'"
:placeHolder="'Enter your username'"
:msg = "user.msg"
v-model="email"
/>
<app-input
class="mt-7"
:id = "password"
:label = "'Password :'"
:text = "'password'"
:placeHolder="'Enter your password'"
:value = "password"
:error = "user.error"
:msg = "user.msg"
v-model="userName"
/>
<app-input
class="mt-7"
:id = "'confpass'"
:label = "'Confirm Password :'"
:text = "'password'"
:placeHolder="'Confirm your password'"
:value = "confirmPass"
:error = "user.error"
:msg = "user.msg"
v-model="confirmPass"
/>
<app-button
class="mt-7 mb-3"
:disabled="false"
:label="'Sign In'"
:variant="'primary'"
@clk="handleSubmit"
/>
<p class="mb-10 text-right">Already have an account?
<router-link
class="text-primary"
:to="{name:'login'}">sign in
</router-link></p>
</auth-wrapper>
</template>
<script>
import AppButton from '../utility/BaseButton.vue';
import AppInput from '../utility/BaseInput.vue';
import AuthWrapper from './part/AuthWrapper.vue';
export default {
name:'AuthSignup',
components: {
AuthWrapper,
AppInput,
AppButton,
},
data(){
return {
userName: '',
email:'',
password: '',
confirmPass: '',
user: {
error: false,
msg: 'invalid input field!',
}
}
},
methods: {
handleSubmit(){
console.log('hello')
}
}
}
</script>
/src/views/Register.vue
<template>
<auth-signup/>
</template>
<script>
import AuthSignup from '../components/auth/AuthSignup.vue'
export default {
name:'RegisterView',
components: {
AuthSignup
},
}
</script>
此代码定义了名为“ registerview”的VUE视图,该视图使用导入的“ AuthSignup”组件显示用户注册表单。 “ authsignup”组件封装在单独的文件和目录中,以进行模块化和易于管理。
通过使用模块化和组件驱动的方法,您不仅可以改善代码组织,而且还为可扩展且可维护的vue.js应用程序奠定了基础。愉快的编码!