Vuejs将动态数据从父组件传递给子组件

Posted

技术标签:

【中文标题】Vuejs将动态数据从父组件传递给子组件【英文标题】:Vuejs Passing dynamic data from parent to child component 【发布时间】:2021-04-22 11:08:35 【问题描述】:

我有一个视图和一个组件。我正在尝试在这里进行身份验证。

作为用户,我输入用户名和密码,点击login。这个emits 向父组件发送信息,它向AWS 中的API 网关发出获取请求。这个获取响应有一个我感兴趣的标头X-Session-Id

我的 emit 位工作正常。

但是,我无法将标头值传递回组件,也无法将new_password_required 设置为true,这将为新密码添加新输入字段,以及替换带有reset password 按钮的login button

我觉得我需要用道具来做这件事,但我无法成功地将值从父母传递给孩子。

另外,重置密码位是否应该有自己的组件?

下面是我的代码。这是我的第一个前端,所以我不熟悉我应该如何分享它(例如与游乐场)。另外,由于我正在学习,我现在正在尝试坚持使用 vanilla vue(我认为我只安装了 vue-router)

父母

<template>
  <div id="app" class="small-container">
    <login-form @login:user="loginUser($event)" />
  </div>
</template>

<script>
import LoginForm from "@/components/LoginForm.vue";

export default 
  name: "Login",
  components: 
    LoginForm
  ,
  data() 
    return 
      session_id: String,
      new_password_required: Boolean
    ;
  ,
  methods: 
    async loginUser(loginEvent) 
      try 
        const response = await fetch(
          process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/login/user",
          
            method: "POST",
            body: JSON.stringify(loginEvent)
          
        );
        const data = await response.json();
        console.log(data);
        if (data.headers["X-Session-Id"] != null) 
          this.session_id = data.headers["X-Session-Id"];
          this.new_password_required = true;
        
       catch (error) 
        console.error(error);
      
    ,
    async resetPassword(resetPasswordEvent) 
      try 
        const response = await fetch(
          process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/reset/user/password",
          
            method: "POST",
            body: JSON.stringify(resetPasswordEvent)
          
        );
        const data = await response.json();
        console.log(data);
       catch (error) 
        console.error(error);
      
    
  
;
</script>

组件

<template>
  <div id="login-form">
    <h1>Serverless App</h1>
    <form>
      <label for="email_address">Email Address:</label><br />
      <input
        v-model="login_details.email_address"
        type="text"
        id="email_address"
        name="email_address"
      /><br />
      <label for="password">Password:</label><br />
      <input
        v-model="login_details.password"
        type="password"
        id="password"
        name="password"
      />
      <label v-if="new_password_required" for="new_password"
        >New Password:</label
      ><br />
      <input
        v-if="new_password_required"
        v-model="login_details.new_password"
        type="password"
        id="new_password"
        name="new_password"
      />
    </form>
    <button v-if="!new_password_required" @click="loginUser($event)">
      Login
    </button>
    <button v-if="new_password_required" @click="resetPassword($event)">
      Reset Password
    </button>
  </div>
</template>

<script>
export default 
  name: "LoginForm",
  props: 
    session_id: String,
    new_password_required: 
      type: Boolean,
      default: () => false
    
  ,
  data() 
    return 
      login_details: 
        email_address: "",
        password: "",
        new_password: ""
      
    ;
  ,

  methods: 
    loginUser() 
      console.log("testing loginUser...");
      const loginEvent = 
        email_address: this.login_details.email_address,
        password: this.login_details.password
      ;
      this.$emit("login:user", loginEvent);
    ,

    resetPassword() 
      console.log("testing resetPassword...");
      const resetPasswordEvent = 
        email_address: this.login_details.email_address,
        password: this.login_details.password,
        new_password: this.login_details.new_password,
        session_id: this.login_details.sessionId
      ;
      this.$emit("reset:Password", resetPasswordEvent);
    
  
;
</script>

【问题讨论】:

您能否说明您打算在子组件中使用X-Session-Id 的原因和方式? 当然。我正在使用 amazon cognito 进行身份验证。登录使用 Cognito InitiateAuth() 方法查看用户状态。初次登录时,状态将为FORCE_CHANGE_PASSWORD。如果不需要更改密码,用户将获得不记名令牌。当需要重置密码时,再次请求AdminRespondToAuthChallenge()方法,该方法以X-Session-Id为参数。该参数通过父类中的resetPassword()方法发送到api网关 如果添加ref attribute to your child,您可以通过this.$refs.childRefName.resetPassword(sessionId)从父级访问实例方法。这是一种方法,可能是最简单的方法。 您希望何时将 new_password_required 设置为 true? @Amaarrockz 我想通了,请参阅下面的答案。如果父级的loginUser() fetch 响应在标题中有X-Session-Id,我想将new_password_required 设置为true。如果后端对 aws cognito InitiateAuth() 方法的请求响应告诉我重置用户密码(这需要会话 ID),则此标头由我的后端 golang lambda 返回。 【参考方案1】:

您的子组件看起来不错,但是,您需要在父组件中传递道具,如下所示:

<login-form @login:user="loginUser($event)" :session-id="xidhere"
    :new-password-required="newPasswordRequired"/>

随着这些值在父组件中更新,子组件也应该更新。

请注意,使用驼峰命名您的道具,然后在您的 html 中使用 kebab-case。

所以你的登录表单属性应该更新为:

  props: 
    sessionId: String,
    newPasswordRequired: 
      type: Boolean,
      default: () => false
    
  ,

另外,当您向父级发送事件时,可能不需要将会话 ID 发送给子级,只需在发送之前将其添加到您的 api 调用中。

【讨论】:

干杯。还没有完全确定 CamelCase here kebab-case there bits。我知道这是一件事,但它已被取消优先级哈。这是一个比我想出的更好的解决方案,而且只有一个组件,因此重复更少。不知道制作一个单独的组件是如何神奇地让我弄清楚我需要用:new-password将道具发送给孩子的@ 干得好。一点一点你就会到达那里!继续加油!【参考方案2】:

想通了。我创建了一个用于重置密码的新子组件。也许它可以干一点?我是新来的。很高兴任何指针:)

家长

<template>
  <div id="app" class="small-container">
    <login-form v-if="!new_password_required" @login:user="loginUser($event)" />
    <reset-password-form
      v-if="new_password_required"
      :session_id="session_id"
      @reset:password="resetPassword($event)"
    />
  </div>
</template>

<script>
import LoginForm from "@/components/LoginForm.vue";
import ResetPasswordForm from "@/components/ResetPasswordForm.vue";

export default 
  name: "Login",
  components: 
    LoginForm,
    ResetPasswordForm
  ,
  data() 
    return 
      session_id: "",
      new_password_required: false
    ;
  ,
  methods: 
    async loginUser(loginEvent) 
      try 
        const response = await fetch(
          process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/login/user",
          
            method: "POST",
            body: JSON.stringify(loginEvent)
          
        );
        const data = await response.json();
        console.log(data);
        if (data.headers["X-Session-Id"] != null) 
          this.session_id = data.headers["X-Session-Id"];
          this.new_password_required = true;
        
       catch (error) 
        console.error(error);
      
    ,

    async resetPassword(resetPasswordEvent) 
      try 
        const response = await fetch(
          process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/reset/user/password",
          
            method: "POST",
            body: JSON.stringify(resetPasswordEvent)
          
        );
        const data = await response.json();
        console.log(data);
       catch (error) 
        console.error(error);
      
    
  
;
</script>

儿童:登录表单

<template>
  <div id="login-form">
    <h1>Serverless Release Dashboard</h1>
    <form>
      <label for="email_address">Email Address:</label><br />
      <input
        v-model="login_details.email_address"
        type="text"
        id="email_address"
        name="email_address"
      /><br />
      <label for="password">Password:</label><br />
      <input
        v-model="login_details.password"
        type="password"
        id="password"
        name="password"
      />
    </form>
    <button @click="loginUser($event)">
      Login
    </button>
  </div>
</template>

<script>
export default 
  name: "LoginForm",
  data() 
    return 
      login_details: 
        email_address: "",
        password: ""
      
    ;
  ,

  methods: 
    loginUser() 
      console.log("testing loginUser...");
      const loginEvent = 
        email_address: this.login_details.email_address,
        password: this.login_details.password
      ;
      this.$emit("login:user", loginEvent);
    
  
;
</script>

儿童:重置密码表格

<template>
  <div id="reset-password-form">
    <h1>Serverless Release Dashboard</h1>
    <form>
      <label for="email_address">Email Address:</label><br />
      <input
        v-model="login_details.email_address"
        type="text"
        id="email_address"
        name="email_address"
      /><br />
      <label for="password">Password:</label><br />
      <input
        v-model="login_details.password"
        type="password"
        id="password"
        name="password"
      />
      <label for="new_password">New Password:</label><br />
      <input
        v-model="login_details.new_password"
        type="password"
        id="new_password"
        name="new_password"
      />
    </form>
    <button @click="resetPassword($event)">
      Reset Password
    </button>
  </div>
</template>

<script>
export default 
  name: "ResetPasswordForm",

  props: 
    email_address: String,
    password: String,
    session_id: String
  ,

  data() 
    return 
      login_details: 
        email_address: "",
        password: "",
        new_password: "",
        session_id: ""
      
    ;
  ,

  methods: 
    resetPassword() 
      console.log("testing resetPassword...");

      const loginEvent = 
        email_address: this.email_address,
        password: this.password,
        new_password: this.login_details.new_password,
        session_id: this.session_id
      ;
      this.$emit("reset:password", loginEvent);
    
  
;
</script>

【讨论】:

以上是关于Vuejs将动态数据从父组件传递给子组件的主要内容,如果未能解决你的问题,请参考以下文章

Vue 组件:如何将数据从父级传递给子级

将一串数据从父组件传递给子组件。 Vue.js 2

将异步结果从父组件传递给子组件反应功能组件

如何在不使用角度的ng的情况下将输入值从父组件传递给子组件?

如果数据属性在 VueJs 中从父组件传递到子组件,则无法将其作为对象进行操作

VueJs:将动态组件作为道具传递给另一个组件并渲染它们