Knowledge Points: v-on, v-for, v-if, props, $emit, dynamic Prop, Class and Style binding
P1 Paging Query
Query parameters: company name, job type, salaryMin salaryMax
Description: The request is made by axios.post with parameters, and the back end uses paging query to return the data of specified number of bars to the front end. MongoDB Limit() is mainly used to limit the number of records read, Skip() skips the specified number of data, the amount of data is very small 1w +.
// paging exports.pageQuery = function (page, pageSize, Model, populate, queryParams, projection, sortParams, callback) { var start = (page - 1) * pageSize; // Get the number of records skip will skip based on page and page Size var $page = { pageNumber: page }; async.parallel({ count: function (done) { // Find out that there are count s in total Model.count(queryParams).exec(function (err, count) { done(err, count); }); }, records: function (done) { // Query to get records of sorted and excluded fields Model.find(queryParams, projection).skip(start).limit(pageSize).populate(populate).sort(sortParams).exec(function (err, doc) { done(err, doc); }); } }, function (err, results) { var list = new Array(); for (let item of results.records) { list.push(item.toObject()) } var count = results.count; $page.pageCount = parseInt((count - 1) / pageSize + 1); // PageCount $page.results = list; // Single page result $page.count = count; // Total Record Volume callback(err, $page); }); };
With the paging function, the query function can only pass in parameters.
Fuzzy Query about MongoDB
// A database command is a regular expression: / parameter/ db.getCollection('jobs').find({company: /NetEase/}) // In js, if you write / data.company / directly, it will be a string. The Model.find({}) function can't recognize it, so you can only use new RegExp() company: new RegExp(data.company)
// Query work exports.findJobs = function (data, cb) { let searchItem = { company: new RegExp(data.company), type: new RegExp(data.type), money: { $gte: data.salaryMin, $lte: data.salaryMax } } for (let item in searchItem) { // Delete the property if the condition is empty if (searchItem[item] === '//') { delete searchItem[item] } } var page = data.page || 1 this.pageQuery(page, PAGE_SIZE, Job, '', searchItem, {_id: 0, __v: 0}, { money: 'asc' }, function (error, data) { ... }) }
P2 Displays Query Results
Explanation: The result of the query is an array of objects, which can be easily displayed by nesting v-for.
// html <div class="searchResult"> <table class="table table-hover"> <tbody class="jobList"> <tr> <th v-for="item in title">{{ item }}</th> </tr> <tr v-for="(item, index) in searchResults" @click="showDesc(index)"> <td v-for="value in item">{{ value }}</td> </tr> </tbody> </table> </div>
// onSubmit() Axios.post('http://localhost:3000/api/searchJobs', searchData) .then(res => { this.searchResults = res.data.results // Single page query results this.page.count = res.data.pageCount // PageCount console.log('PageCount' + this.page.count) // Total data volume ... }) .catch(err => { console.log(err) })
P3 Details Card
Description: The specific content is displayed by clicking on the single-line data to display the customized detail box component DescMsg.
Composition: Mask + Content Box
Idea: Click on the single line data in the parent component SearchJob and pass the selected row data jobDesc and showMsg: true to the child component DescMsg through props. Click on the rest of the child component DescMsg except the details box, and use $emit('hideMsg') to trigger the closing details page event. The parent component uses v-on directly to listen for the events triggered by the child component where the child component is used, and set showMsg: false to close the details page.
// Using DescMsg in parent components <DescMsg :jobDesc="jobDesc" :showMsg="showMsg" v-on:hideMsg="hideJobDesc"></DescMsg>
// Display Details Box showDesc (index) { let item = this.searchResults[index] this.jobDesc = [ { title: 'Title', value: item.posname }, { title: 'company', value: item.company }, { title: 'A monthly salary', value: item.money }, { title: 'place', value: item.area }, { title: 'Release time', value: item.pubdate }, { title: 'Minimum educational background', value: item.edu }, { title: 'Hands-on background', value: item.exp }, { title: 'details', value: item.desc }, { title: 'welfare', value: item.welfare }, { title: 'Position Category', value: item.type }, { title: 'Recruitment', value: item.count } ] this.showMsg = true }, // Close Details Box hideJobDesc () { this.showMsg = false }
// Subcomponent DescMsg <template> <div class="wrapper" v-if="showMsg"> <div class="shade" @click="hideShade"></div> <div class="msgBox"> <h4 class="msgTitle">Details</h4> <table class="table table-hover"> <tbody class="jobList"> <tr v-for="item in jobDesc" :key="item.id"> <td class="title">{{ item.title }}</td> <td class="ctn">{{ item.value }}</td> </tr> </tbody> </table> <div class="ft"> <button type="button" class="btn btn-primary" @click="fllow">follow</button> </div> </div> </div> </template> <script> export default { data () { return { } }, props: { jobDesc: { type: Array, default: [] }, showMsg: { type: Boolean, default: false } }, methods: { hideShade () { this.$emit('hideMsg') }, fllow () { alert('1') } } } </script>
P4 page number
Description: According to the total number of pages count ed by the query, it is stipulated that the maximum number of pages should be displayed at one time.
Idea: Render the page number by v-for, i.e. v-for="(item, index) of pageList", and bind Class for each li, i.e. class="{active: item.active}. When the number of pages is greater than 10, click on the nth page number greater than 6, the number of pages moves 1 to the right as a whole, otherwise it moves 1 to the left as a whole. To click item.active = true after a page number, add a style. active to the page number.
html
<!-- Bottom page number column --> <div class="pageButtons"> <nav aria-label="Page navigation"> <ul class="pagination"> <li :class="{disabled: minPage}"> <a aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> <li v-for="(item, index) of pageList" :class="{active: item.active}"> <a @click="onSubmit(index)">{{ item.value }}</a> </li> <li :class="{disabled: maxPage}"> <a aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> </div>
js
export default { data () { return { page: { selected: 0, // Select the number of pages count: 0, // PageCount size: 10 // Maximum number of display pages }, pageList: [ {active: false, value: 1} // Default contains page number 1 ] } }, methods: { // Index stands for page number index from left to start. Okay, I'm confused, up to 10. onSubmit (index) { if (index === -1) { // index is - 1, which represents the event triggered by clicking the query button directly to initialize the data. index = 0 this.page.selected = 0 this.pageList = [ {active: false, value: 1} ] } Axios.post('http://localhost:3000/api/searchJobs', searchData) .then(res => { this.page.count = res.data.pageCount // PageCount let pageNumber = 1 // Default page 1 // If the index >= 6 and the last page number displayed is less than the total number of pages, then move 1 backward as a whole, and the selected page number moves 1 to the left accordingly, that is index-- if (index >= 6 && (this.page.count - this.pageList[9].value) > 0) { pageNumber = this.pageList[1].value index-- } else if (index < 6 && this.pageList[0].value !== 1) { pageNumber = this.pageList[0].value - 1 index++ } this.pageList = [] // Initialize pageList and then render it again this.page.size = (this.page.count > 10) ? 10 : this.page.count for (let i = 0; i < this.page.size; i++) { let item = { active: false, value: pageNumber } pageNumber++ this.pageList.push(item) } // Change the current selected page number subscript style, index represents the index number from left to start, up to 10 this.pageList[this.page.selected].active = false this.pageList[index].active = true this.page.selected = index console.log(searchData.page) }) .catch(err => { console.log(err) }) } } }