vue3模块化引用组件和引用ts,调用ts中的接口

以简单的登录功能为例子

1.在util中创建loginValidators.ts

javascript 复制代码
import { ref, reactive  } from 'vue'

interface User{
    email: string;
    password: string;
}

export const loginUser=reactive<User>({
    email: '',
    password: ''
})

interface Rules{
    email: {
        required: boolean;
        message: string;
        trigger: string;
    }[];
    password: ({
        required: boolean;
        message: string;
        trigger: string;
        min?: undefined;
        max?: undefined;
    } | {
        min: number;
        max: number;
        message: string;
        trigger: string;
        required?: undefined;
    })[];
}
export const rules=reactive<Rules>({
    email: [
        { required: true, message: '密码不得为空', trigger: 'blur' }
        // {
        //   required: true,
        //   type: 'email',
        //   message: 'email格式错误',
        //   trigger: 'blur'
        // }
      ],
      password: [
        { required: true, message: '密码不得为空', trigger: 'blur' },
        { min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' }
      ]
})

2.在登录页面中引用刚才创建的验证ts

3.创建登录组件

传入得参数(此步骤在登录界面引用登录组件后传入的参数:查看第4步骤)

就可以使用ts中创建的参数

登录组件代码(可看可不看)

javascript 复制代码
<template>
  <!-- 登录 -->
  <el-form
    :model="loginUser"
    :rules="rules"
    ref="loginForm"
    label-width="100px"
    class="login-form sign-in-form"
  >
    <el-form-item label="邮箱" prop="email">
      <el-input v-model="loginUser.email" placeholder="Enter Email..." />
    </el-form-item>
    <el-form-item label="密码" prop="password">
      <el-input
        v-model="loginUser.password"
        type="password"
        placeholder="Enter Password..."
      />
    </el-form-item>
    <el-form-item>
      <el-button
        @click="handleLogin('loginForm')"
        type="primary"
        class="submit-btn"
        >提交</el-button
      >
    </el-form-item>
    <!-- 找回密码 -->
    <el-form-item>
      <p class="tiparea">忘记密码<a>立即找回</a></p>
    </el-form-item>
  </el-form>
</template>

<script lang="ts">
import { getCurrentInstance } from 'vue'
import { useRouter } from 'vue-router'
import { login } from '@/api/login'
export default {
  name: 'LoginForm',
  props: {
    loginUser: {
      type: Object,
      required: true
    },
    rules: {
      type: Object,
      required: true
    }
  },
  setup(props: any) {
    const router = useRouter()
    // 通过解构getCurrentInstance,获取this,这里的this就是ctx
    // @ts-ignore
    const { ctx,proxy } = getCurrentInstance()
    // 触发登录方法
    const handleLogin = (formName: string) => {
      console.log(ctx)
      ctx.$refs[formName].validate(async (valid: boolean) => {
        if (valid) {
          //await是等待的意思
          const res = await login(props.loginUser)
          // if(res==false){
          //   proxy.$message.warning("res是方法返回来的数据")
          // }else{
          //   proxy.$message.success("123")
          //   router.push('/home')
          // } 
          proxy.$message.success("123")
          router.push('/home')
        } else {
          console.log('error submit!')
          return false
        }
      })
    }
    return { handleLogin }
  }
}
</script>
<style scoped>
/* register */
.login-form,
.register-form {
  background-color: #fff;
  padding: 50px 80px 20px 20px;
  border-radius: 5px;
  box-shadow: 0px 5px 10px #cccc;
}

.submit-btn {
  width: 100%;
}
.tiparea {
  text-align: right;
  font-size: 12px;
  color: #333;
  width: 100%;
}
.tiparea a {
  color: #409eff;
}
</style>

4.在登录页面中引入登录组件

登录界面代码(可看可不看)

javascript 复制代码
<template>
  <div class="container" :class="{ 'sign-up-mode': signUpMode }">
    <!-- form表单容器 -->
    <div class="form-container">
      <div class="signin-signup">
        <!-- 登录 -->
        <LoginForm :loginUser="loginUser" :rules="rules"></LoginForm>
          <!-- 注册 -->
        <RegisterForm :registerUser="registerUser" :registerRules="registerRules"></RegisterForm>
      </div>
    </div>
    <!-- 左右切换动画 -->
    <div class="panels-container">
      <div class="panel left-panel">
        <div class="content">
          <h3>Row,row,row your boat</h3>
          <p>Gentlely down the stream</p>
          <button @click="signUpMode = !signUpMode" class="btn transparent">
            注册
          </button>
        </div>
        <!-- <img src="@/assets" alt=""> -->
      </div>
      <div class="panel right-panel">
        <div class="content">
          <h3>Merrily,merrily,merrily,merrily,</h3>
          <p>Life is but a dream</p>
          <button @click="signUpMode = !signUpMode" class="btn transparent">
            登录
          </button>
        </div>
        <!-- <img src="@/assets" alt=""> -->
      </div>
    </div>
    <!-- <el-form
           :model="loginUser"
           :rules="rules"
           ref="loginForm"
           label-width="100px"
           class="login-form sign-in-form"
          >
             <el-form-item label="邮箱" prop="email">
               <el-input v-model="loginUser.email" placeholder="Enter Email..." />
             </el-form-item>
             <el-form-item label="密码" prop="password">
               <el-input
                v-model="loginUser.password"
                type="password"
                placeholder="Enter Password..."
               />
             </el-form-item>
             <el-form-item>
                <el-button type="primary" class="submit-btn" @click="handleLogin('loginForm')">提交</el-button>
             </el-form-item>
             
             <el-form-item>
                <p class="tiparea">忘记密码<a>立即找回</a></p>
             </el-form-item>
          </el-form> -->
  </div>
</template>

<script lang="ts">
import {ref,reactive,getCurrentInstance } from 'vue'
import {loginUser,rules} from '@/utils/loginValidators' //登录验证规则
import {registerUser ,registerRules } from '@/utils/registerValidator' //注册验证规则
import LoginForm from '@/components/LoginForm.vue' //登录组件
import RegisterForm from '@/components/RegisterForm.vue' //注册组件

export default {
  name: 'LoginRegister',
  components:{LoginForm,RegisterForm},

  setup() {
    // 登录/注册模式
    const signUpMode = ref(false)
    // 通过解构getCurrentInstance,获取this,这里的this就是ctx
    // @ts-ignore
    // const { ctx } = getCurrentInstance()
    // const loginUser=reactive({
    //     email:'',
    //     password:''
    // })
    // //校验规则
    // const rules=reactive({
    //     email:[
    //         {
    //            required: true,
    //            type: 'email',
    //            message: 'email格式错误',
    //            trigger: 'blur'
    //         }
    //     ],
    //     password:[
    //         {required:true,message:'密码不能为空',trigger:'blur'},
    //         { min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' }
    //     ]
    // })
    //提交
    // const handleLogin=(formName:string)=>{
    //     console.log( ctx.loginUser.password)
    //     ctx.$refs[formName].validate((valid:boolean)=>{
    //         if (valid) {
    //             console.log("提交吧")
    //         }else{
    //             console.log("不提交了")
    //             return false
    //         }
    //     })
    // }

    return {signUpMode,loginUser,rules,registerUser,registerRules}
  }
}
</script>
<style scoped>
.container {
  position: relative;
  width: 100%;
  min-height: 100vh;
  background-color: #fff;
  overflow: hidden;
}
.form-container {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}
.signin-signup {
  position: relative;
  top: 50%;
  left: 75%;
  transform: translate(-50%, -50%);
  width: 44%;
  transition: 1s 0.7s ease-in-out;
  display: grid;
  grid-template-columns: 1fr;
  z-index: 5;
}

/* 左右切换动画 */
.social-text {
  padding: 0.7rem 0;
  font-size: 1rem;
}

.social-media {
  display: flex;
  justify-content: center;
}

.social-icon {
  height: 46px;
  width: 46px;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0 0.45rem;
  color: #333;
  border-radius: 50%;
  border: 1px solid #333;
  text-decoration: none;
  font-size: 1.1rem;
  transition: 0.3s;
}

.social-icon:hover {
  color: #4481eb;
  border-color: #4481eb;
}

.btn {
  width: 150px;
  background-color: #5995fd;
  border: none;
  outline: none;
  height: 49px;
  border-radius: 49px;
  color: #fff;
  text-transform: uppercase;
  font-weight: 600;
  margin: 10px 0;
  cursor: pointer;
  transition: 0.5s;
}

.btn:hover {
  background-color: #4d84e2;
}
.panels-container {
  position: absolute;
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}

.container:before {
  content: '';
  position: absolute;
  height: 2000px;
  width: 2000px;
  top: -10%;
  right: 48%;
  transform: translateY(-50%);
  background-image: linear-gradient(-45deg, #4481eb 0%, #04befe 100%);
  transition: 1.8s ease-in-out;
  border-radius: 50%;
  z-index: 6;
}

.image {
  width: 100%;
  transition: transform 1.1s ease-in-out;
  transition-delay: 0.4s;
}

.panel {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: space-around;
  text-align: center;
  z-index: 6;
}

.left-panel {
  pointer-events: all;
  padding: 3rem 17% 2rem 12%;
}

.right-panel {
  pointer-events: none;
  padding: 3rem 12% 2rem 17%;
}

.panel .content {
  color: #fff;
  transition: transform 0.9s ease-in-out;
  transition-delay: 0.6s;
}

.panel h3 {
  font-weight: 600;
  line-height: 1;
  font-size: 1.5rem;
}

.panel p {
  font-size: 0.95rem;
  padding: 0.7rem 0;
}

.btn.transparent {
  margin: 0;
  background: none;
  border: 2px solid #fff;
  width: 130px;
  height: 41px;
  font-weight: 600;
  font-size: 0.8rem;
}

.right-panel .image,
.right-panel .content {
  transform: translateX(800px);
}

/* ANIMATION */

.container.sign-up-mode:before {
  transform: translate(100%, -50%);
  right: 52%;
}

.container.sign-up-mode .left-panel .image,
.container.sign-up-mode .left-panel .content {
  transform: translateX(-800px);
}

.container.sign-up-mode .signin-signup {
  left: 25%;
}

.container.sign-up-mode form.sign-up-form {
  opacity: 1;
  z-index: 2;
}

.container.sign-up-mode form.sign-in-form {
  opacity: 0;
  z-index: 1;
}

.container.sign-up-mode .right-panel .image,
.container.sign-up-mode .right-panel .content {
  transform: translateX(0%);
}

.container.sign-up-mode .left-panel {
  pointer-events: none;
}

.container.sign-up-mode .right-panel {
  pointer-events: all;
}

@media (max-width: 870px) {
  .container {
    min-height: 800px;
    height: 100vh;
  }
  .signin-signup {
    width: 100%;
    top: 95%;
    transform: translate(-50%, -100%);
    transition: 1s 0.8s ease-in-out;
  }

  .signin-signup,
  .container.sign-up-mode .signin-signup {
    left: 50%;
  }

  .panels-container {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr 2fr 1fr;
  }

  .panel {
    flex-direction: row;
    justify-content: space-around;
    align-items: center;
    padding: 2.5rem 8%;
    grid-column: 1 / 2;
  }

  .right-panel {
    grid-row: 3 / 4;
  }

  .left-panel {
    grid-row: 1 / 2;
  }

  .image {
    width: 200px;
    transition: transform 0.9s ease-in-out;
    transition-delay: 0.6s;
  }

  .panel .content {
    padding-right: 15%;
    transition: transform 0.9s ease-in-out;
    transition-delay: 0.8s;
  }

  .panel h3 {
    font-size: 1.2rem;
  }

  .panel p {
    font-size: 0.7rem;
    padding: 0.5rem 0;
  }

  .btn.transparent {
    width: 110px;
    height: 35px;
    font-size: 0.7rem;
  }

  .container:before {
    width: 1500px;
    height: 1500px;
    transform: translateX(-50%);
    left: 30%;
    bottom: 68%;
    right: initial;
    top: initial;
    transition: 2s ease-in-out;
  }

  .container.sign-up-mode:before {
    transform: translate(-50%, 100%);
    bottom: 32%;
    right: initial;
  }

  .container.sign-up-mode .left-panel .image,
  .container.sign-up-mode .left-panel .content {
    transform: translateY(-300px);
  }

  .container.sign-up-mode .right-panel .image,
  .container.sign-up-mode .right-panel .content {
    transform: translateY(0px);
  }

  .right-panel .image,
  .right-panel .content {
    transform: translateY(300px);
  }

  .container.sign-up-mode .signin-signup {
    top: 5%;
    transform: translate(-50%, 0);
  }
}

@media (max-width: 570px) {
  form {
    padding: 0 1.5rem;
  }

  .image {
    display: none;
  }
  .panel .content {
    padding: 0.5rem 1rem;
  }
  .container {
    padding: 1.5rem;
  }

  .container:before {
    bottom: 72%;
    left: 50%;
  }

  .container.sign-up-mode:before {
    bottom: 28%;
    left: 50%;
  }
}

/* 控制login & register显示 */
form {
  padding: 0rem 5rem;
  transition: all 0.2s 0.7s;
  overflow: hidden;
}

form.sign-in-form {
  z-index: 2;
}

form.sign-up-form {
  opacity: 0;
  z-index: 1;
}

/* register */
.loginForm,
.registerForm {
  margin-top: 20px;
  background-color: #fff;
  padding: 20px 40px 20px 20px;
  border-radius: 5px;
  box-shadow: 0px 5px 10px #cccc;
}

.submit-btn {
  width: 100%;
}
.tiparea {
  text-align: right;
  font-size: 12px;
  color: #333;
  width: 100%;
}
.tiparea a {
  color: #409eff;
}
</style>

5.创建接口login.ts

自定义方法和接口方法 对应注释的部分

javascript 复制代码
import axios from '@/utils/http'

// 注册接口
//接口方法
export function login(params: any) {
  return axios({
    url: '/api/v1/auth/register',
    method: 'post',
    headers: {
      'Content-Type': 'application/json;charset=UTF-8'
    },
    data: params
  })
}
//自定义方法
// export function login(params: any) {
//   console.log(params)
//   if(params.email=="123456" && params.password=="123456"){
//     return true
//   }else{
//     return false
//   }
// }

6.提交方法(引用ts)

对应注释的部分

相关推荐
Dream-Y.ocean1 小时前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
Csvn2 小时前
性能监控
前端
Highcharts.js2 小时前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
Csvn2 小时前
构建工具
前端
FRing033 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Java小卷3 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
kyriewen5 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒5 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫6 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
jerrywus6 小时前
我用 GPT-6.1-sol 做了台会讲解的 3D 售货机:60 罐饮料,一口没喝上
前端·agent·claude