Vue.js子组件Props数组排序报错问题及实现需求
Let's walk through fixing your sorting problem—there are a handful of small issues in your code that are causing the error and preventing proper sorting:
1. You're Trying to Directly Modify Props (Plus a Typo!)
First, this.job.application has a typo—it should be this.job.applications (missing an 's'). Even bigger issue: Vue doesn't allow direct modification of props (they follow one-way data flow from parent to child). Changing props directly will throw errors and break reactivity. Instead, we'll use a computed property to handle sorting without touching the original prop data.
2. Incorrect Property Access
Your sort callback uses a.sortBy—this tries to access a property named sortBy on your application objects, not the dynamic sortBy variable you're passing. You need to use bracket notation: a[sortBy] to access the property matching your sort key.
3. String Sorting Doesn't Work with -
Since you're sorting by name (a string), using a[sortBy] - b[sortBy] will result in NaN (you can't subtract strings). Use localeCompare() for proper string sorting instead.
4. You're Not Handling Sort Direction
Your changeSort method doesn't actually respect the sortDirection parameter—it just runs a single sort direction. We need to flip the comparison result based on whether we want ascending or descending order.
Corrected Code
Here's the updated component with fixes applied:
Template Changes
Update the table body to use our sorted computed property, and fix the header arrow display to show an unsorted icon when not active:
<template> <div class="modal-backdrop"> <div class="modal"> <header class="modal-header"> <slot name="header"> <h3>{{job.name}}</h3> <button v-if="application.name" type="button" class="btn-close" @click="back"> <i class="fa fa-arrow-left"></i> Back </button> <button type="button" class="btn-close" @click="close"> x </button> </slot> </header> <section class="modal-body"> <div class="row"> <div v-if="!application.name" class=" col-12 applications-list"> <table class="table table-bordered"> <thead> <tr> <th>Name <i @click="changeSort('name', 'desc')" v-if="sortBy === 'name' && sortDirection === 'asc'" class="fa fa-sort-up"></i> <i @click="changeSort('name', 'asc')" v-if="sortBy === 'name' && sortDirection === 'desc'" class="fa fa-sort-down"></i> <i v-else class="fa fa-unsorted"></i> </th> <th>Email <i class="fa fa-unsorted"></i></th> <th>Date <i class="fa fa-unsorted"></i></th> </tr> </thead> <tbody> <!-- Use the sorted computed property here --> <tr class="application-row" v-for="application in sortedApplications" :key="application.id" :application="application" @click="getApplication(application)"> <td>{{application.name}}</td> <td>{{application.email}}</td> <td>Applied {{moment(application.created_at).fromNow()}}</td> </tr> </tbody> </table> </div> <!-- Rest of your template remains the same --> <div v-if="application.name" class="col-12 applicant"> <small>Applied {{moment(application.created_at).fromNow()}}</small> <h4 v-if="application.name">Name</h4><p>{{application.name}}</p> <h4 v-if="application.email">Email</h4><p>{{application.email}}</p> <h4 v-if="application.phone">Phone</h4><p>{{application.phone}}</p> <h4 v-if="application.linkedin">Linkedin</h4><p>{{application.linkedin}}</p> <h4 v-if="application.cover_letter">Coverletter</h4><p v-html="application.cover_letter"></p> </div> </div> </section> <footer class="modal-footer"> </footer> </div> </div> </template>
Script Changes
Add a computed property for sorted applications, and simplify the changeSort method to just update our sort state:
<script> import moment from 'moment'; export default { name: 'ApplicationsList', props:['job'], data(){ return{ application: {name:'', email: '', created_at:'', phone: '', linkedin: '', cover_letter: ''}, sortBy:'name', sortDirection:'asc', } }, computed: { sortedApplications() { // Create a copy of the original array to avoid modifying the prop const applications = [...this.job.applications]; return applications.sort((a, b) => { const valueA = a[this.sortBy]; const valueB = b[this.sortBy]; // Handle string sorting (like name/email) if (typeof valueA === 'string') { const compareResult = valueA.localeCompare(valueB); // Reverse result if descending return this.sortDirection === 'asc' ? compareResult : -compareResult; } // Handle number/date sorting (if needed later) return this.sortDirection === 'asc' ? valueA - valueB : valueB - valueA; }); } }, methods:{ moment, close(){ this.$emit('closeApplicationsRequest'); }, getApplication(application){ this.application = application; }, back(){ this.application = ''; }, changeSort(sortBy, sortDirection){ // Just update our sort state—computed property will handle the rest this.sortBy = sortBy; this.sortDirection = sortDirection; } }, } </script>
Key Improvements Explained
- Computed Property:
sortedApplicationsis reactive—any change tosortBy,sortDirection, or the originaljob.applicationsprop will automatically re-sort the list. - No Prop Modification: We create a copy of the applications array with
[...this.job.applications]so we never mutate the original prop data. - Proper Sorting Logic: Uses
localeCompare()for strings and handles ascending/descending direction correctly. - Cleaner State Management: The
changeSortmethod just updates our sort variables instead of trying to sort directly, keeping logic separated.
内容的提问来源于stack exchange,提问作者Luiz Wynne

