【问题标题】:What causes the failure of a custom filter in this Vue 3 application?是什么导致这个 Vue 3 应用程序中的自定义过滤器失败?
【发布时间】:2021-11-28 14:10:57
【问题描述】:

我正在使用 Vue 3 开发 Users CRUD 应用程序。我想以相反的顺序显示用户(最新添加的内容应该在顶部),为此,我使用自定义过滤器如下:

reverse(array) {
  return array.slice().reverse();
}

我收到Property "reverse" was accessed during render but is not defined on instance 错误,而不是预期的结果。

const usersApp = {
  data() {
    return {
      users: [{
          id: 1,
          first_name: "John",
          last_name: "Doe",
          email: "john.doe@gmail.com"
        },
        {
          id: 2,
          first_name: "Jane",
          last_name: "Doe",
          email: "jane.doe@gmail.com"
        }
      ],
      formData: {
        first_name: "",
        last_name: "",
        email: ""
      },
      formErrors: [],
      userAdded: false
    };
  },
  methods: {
    isNotEmpty() {
      return (
        this.formData.first_name &&
        this.formData.last_name &&
        this.formData.email
      );
    },
    isEmail(email) {
      return String(email)
        .toLowerCase()
        .match(
          /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
        );
    },
    formValidation() {
      this.formErrors = [];

      if (!this.isNotEmpty()) {
        this.formErrors.push("There are empty filelds");
      }

      if (this.isNotEmpty() && !this.isEmail(this.formData.email)) {
        this.formErrors.push("The email is invalid");
      }
    },
    resetAddFormData() {
      this.formData.first_name = "";
      this.formData.last_name = "";
      this.formData.email = "";
      this.userAdded = false;
    },
    addUser() {
      // Validate form data
      this.formValidation();

      // Make New User
      let newUser = {
        first_name: this.formData.first_name,
        last_name: this.formData.last_name,
        email: this.formData.email
      };

      // Add new user
      if (!this.formErrors.length) {
        this.users.push(newUser);
        this.userAdded = true;
        window.setTimeout(this.resetAddFormData, 1000);
      }
    }
  },
  watch: {
    users() {
      this.users();
    }
  },
  filters: {
    reverse(array) {
      return array.slice().reverse();
    }
  }
};

Vue.createApp(usersApp).mount("#app");
.logo {
  width: 30px;
}

.nav-item {
  width: 100%;
}

@media (min-width: 768px) {
  .nav-item {
    width: auto;
  }
}

.user-row {
  transition: all 1s ease;
  opacity: 1;
  height: auto;
}

.user-row-active {
  opacity: 0;
  height: 0;
}

.alert {
  padding: 0.6rem 0.75rem;
  text-align: center;
  font-weight: 600;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script src="https://unpkg.com/vue@next"></script>


<div id="app">
  <nav class="navbar navbar-expand-sm bg-dark navbar-dark">
    <!-- Brand -->
    <a class="navbar-brand p-0" href="#">
      <img src="https://www.pngrepo.com/png/303293/180/bootstrap-4-logo.png" alt="" class="logo">
    </a>

    <!-- Links -->
    <div class="navbar-nav w-100">
      <ul class="navbar-nav ml-auto" id="navbarSupportedContent">
        <li class="nav-item">
          <button type="button" class="btn btn-sm btn-success" data-toggle="modal" data-target="#exampleModalCenter">
            Add user
          </button>
        </li>
      </ul>
    </div>
  </nav>

  <div class="container">
    <div class="card my-2">
      <h5 class="card-header px-2">Users</h5>
      <div class="card-body p-0">
        <table class="table table-striped m-0">
          <thead>
            <tr>
              <th>Firstname</th>
              <th>Lastname</th>
              <th>Email</th>
            </tr>
          </thead>
          <tbody name="users-table" is="transition-group">
            <tr v-for="user in users | reverse" :key="user.id" class="user-row">
              <td>{{user.first_name}}</td>
              <td>{{user.last_name}}</td>
              <td>{{user.email}}</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  </div>

  <div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <h3 class="modal-title h6" id="exampleModalLongTitle">New User</h3>
          <button type="button" class="close" data-dismiss="modal" aria-label="Close" @click="resetAddFormData">
            <span aria-hidden="true">&times;</span>
          </button>
        </div>
        <div class="modal-body">
          <div v-if="this.formErrors.length">
            <div v-for="error in formErrors" class="alert alert-danger">
              {{error}}
            </div>
          </div>
          <div v-if="userAdded" class="alert alert-success">User added successfully!</div>
          <form @submit.prevent="addUser" novalidate>
            <div class="form-group mb-2">
              <input type="text" class="form-control input-sm" placeholder="First name" v-model="formData.first_name">
            </div>
            <div class="form-group mb-2">
              <input type="text" class="form-control input-sm" placeholder="Last name" v-model="formData.last_name">
            </div>
            <div class="form-group mb-2">
              <input type="email" class="form-control input-sm" placeholder="Email address" v-model="formData.email">
            </div>
            <div class=" mt-2">
              <button type="submit" class="btn btn-sm btn-block btn-success">Submit</button>
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>

</div>

问题:

  1. 我做错了什么?
  2. 是否有更好的替代方法来为此使用过滤器?

【问题讨论】:

    标签: javascript vue.js vuejs3


    【解决方案1】:

    好吧,正如docs 所说的过滤器可用于常见的文本格式,因此您不能在数组元素上使用它,因此获得反转数组的替代解决方案是使用computed properties

    所以你可以像这样创建一个计算属性:

    reversedUsers() {
      return this.users.slice().reverse();
    }
    

    然后得到如下结果:

    const usersApp = {
      data() {
        return {
          users: [{
              id: 1,
              first_name: "John",
              last_name: "Doe",
              email: "john.doe@gmail.com"
            },
            {
              id: 2,
              first_name: "Jane",
              last_name: "Doe",
              email: "jane.doe@gmail.com"
            }
          ],
          formData: {
            first_name: "",
            last_name: "",
            email: ""
          },
          formErrors: [],
          userAdded: false
        };
      },
      methods: {
        isNotEmpty() {
          return (
            this.formData.first_name &&
            this.formData.last_name &&
            this.formData.email
          );
        },
        isEmail(email) {
          return String(email)
            .toLowerCase()
            .match(
              /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
            );
        },
        formValidation() {
          this.formErrors = [];
    
          if (!this.isNotEmpty()) {
            this.formErrors.push("There are empty filelds");
          }
    
          if (this.isNotEmpty() && !this.isEmail(this.formData.email)) {
            this.formErrors.push("The email is invalid");
          }
        },
        resetAddFormData() {
          this.formData.first_name = "";
          this.formData.last_name = "";
          this.formData.email = "";
          this.userAdded = false;
        },
        addUser() {
          // Validate form data
          this.formValidation();
    
          // Make New User
          let newUser = {
            first_name: this.formData.first_name,
            last_name: this.formData.last_name,
            email: this.formData.email
          };
    
          // Add new user
          if (!this.formErrors.length) {
            this.users.push(newUser);
            this.userAdded = true;
            window.setTimeout(this.resetAddFormData, 1000);
          }
        }
      },
      watch: {
        users() {
          this.users();
        }
      },
      computed: {
        reversedUsers() {
          return this.users.slice().reverse();
        }
      }
    };
    
    Vue.createApp(usersApp).mount("#app");
    .logo {
      width: 30px;
    }
    
    .nav-item {
      width: 100%;
    }
    
    @media (min-width: 768px) {
      .nav-item {
        width: auto;
      }
    }
    
    .user-row {
      transition: all 1s ease;
      opacity: 1;
      height: auto;
    }
    
    .user-row-active {
      opacity: 0;
      height: 0;
    }
    
    .alert {
      padding: 0.6rem 0.75rem;
      text-align: center;
      font-weight: 600;
    }
    <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    <script src="https://unpkg.com/vue@next"></script>
    
    
    <div id="app">
      <nav class="navbar navbar-expand-sm bg-dark navbar-dark">
        <!-- Brand -->
        <a class="navbar-brand p-0" href="#">
          <img src="https://www.pngrepo.com/png/303293/180/bootstrap-4-logo.png" alt="" class="logo">
        </a>
    
        <!-- Links -->
        <div class="navbar-nav w-100">
          <ul class="navbar-nav ml-auto" id="navbarSupportedContent">
            <li class="nav-item">
              <button type="button" class="btn btn-sm btn-success" data-toggle="modal" data-target="#exampleModalCenter">
                Add user
              </button>
            </li>
          </ul>
        </div>
      </nav>
    
      <div class="container">
        <div class="card my-2">
          <h5 class="card-header px-2">Users</h5>
          <div class="card-body p-0">
            <table class="table table-striped m-0">
              <thead>
                <tr>
                  <th>Firstname</th>
                  <th>Lastname</th>
                  <th>Email</th>
                </tr>
              </thead>
              <tbody name="users-table" is="transition-group">
                <tr v-for="user in reversedUsers" :key="user.id" class="user-row">
                  <td>{{user.first_name}}</td>
                  <td>{{user.last_name}}</td>
                  <td>{{user.email}}</td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>
      </div>
    
      <div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered" role="document">
          <div class="modal-content">
            <div class="modal-header">
              <h3 class="modal-title h6" id="exampleModalLongTitle">New User</h3>
              <button type="button" class="close" data-dismiss="modal" aria-label="Close" @click="resetAddFormData">
                <span aria-hidden="true">&times;</span>
              </button>
            </div>
            <div class="modal-body">
              <div v-if="this.formErrors.length">
                <div v-for="error in formErrors" class="alert alert-danger">
                  {{error}}
                </div>
              </div>
              <div v-if="userAdded" class="alert alert-success">User added successfully!</div>
              <form @submit.prevent="addUser" novalidate>
                <div class="form-group mb-2">
                  <input type="text" class="form-control input-sm" placeholder="First name" v-model="formData.first_name">
                </div>
                <div class="form-group mb-2">
                  <input type="text" class="form-control input-sm" placeholder="Last name" v-model="formData.last_name">
                </div>
                <div class="form-group mb-2">
                  <input type="email" class="form-control input-sm" placeholder="Email address" v-model="formData.email">
                </div>
                <div class=" mt-2">
                  <button type="submit" class="btn btn-sm btn-block btn-success">Submit</button>
                </div>
              </form>
            </div>
          </div>
        </div>
      </div>
    
    </div>

    【讨论】:

      猜你喜欢
      • 2022-01-05
      • 1970-01-01
      • 1970-01-01
      • 2021-01-12
      • 2022-01-24
      • 1970-01-01
      • 2012-04-20
      • 1970-01-01
      • 2019-04-16
      相关资源
      最近更新 更多