简体   繁体   English

如何使用 vue.js 处理动态表单

[英]How to process a dynamic form using vue.js

So I'm building a filter option for my website and its options are loaded from DB and because of this, I believe I can't use a normal v-model to do the job.所以我正在为我的网站构建一个过滤器选项,它的选项是从数据库加载的,因此,我相信我不能使用普通的v-model来完成这项工作。

I have different filter parameters such as Categories and Companies and their options are loaded from DB so they can have 5 or 10 options.我有不同的过滤器参数,例如CategoriesCompanies ,它们的选项是从数据库加载的,因此它们可以有 5 或 10 个选项。

Screenshot of the filter in the website (Better for visualization):网站中过滤器的屏幕截图(更好的可视化):

在此处输入图像描述

My code:我的代码:

 body { position: relative; }.save_filter{ height: 40px; }.save_filter button { background: black; color: white; width: 100%; height: 100%; border: 0; border-radius: 5px; cursor: pointer; }.see_offer{ position: absolute; bottom: 0; width: 100%; height: 50px; background-color: black; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }.see_offer span{ position: relative; left: calc(50% - 39.93px); top: calc(50% - 9.2px); color: white; }.main-body { max-width: 1270px; font-family: "Ubuntu", sans-serif; margin: 0 auto; }.page-content { padding-top: 70px; position: relative; margin: 0 auto; }.page-content.container { display: flex; justify-content: space-evenly; }.page-content.first-section.category-title span { font-family: "Segoe UI Regular"; font-style: normal; font-weight: 600; font-size: 23px; letter-spacing: 0.21em; color: #1D1D25; position: relative; }.page-content.first-section.category-title span::after { content: ""; display: block; position: absolute; border: 2px solid #1D1D25; border-radius: 20px; width: 96%; bottom: -11px; left: 0; }.page-content.second-section { padding-top: 44px; display: flex; }.page-content.second-section.left { flex: 1; }.page-content.second-section.right { flex: 3; }.page-content.second-section.left.left-container { width: 200px; min-width: 200px; }.second-section.left.left-container.filter { display: flex; }.second-section.combo-group { position: relative; width: 100%; }.second-section.combo-group select { font-family: "Ubuntu", sans-serif; font-size: 14px; color: black; width: 100%; box-sizing: border-box; border-radius: 7px; padding: 0 20px; height: 34px; -webkit-appearance: none; -moz-appearance: none; border: 1px solid #1D1D25; background-image: linear-gradient(45deg, transparent 50%, #010101 50%), linear-gradient(135deg, #010101 50%, transparent 50%); background-position: calc(100% - 20px) calc(1em + 1px), calc(100% - 15px) calc(1em + 1px), 100% 0px; background-size: 5px 5px, 5px 5px, 2.5em 2.5em; background-repeat: no-repeat; background-color: white; }.second-section.combo-group select:focus { border-color: lightblue; }.second-section.left.left-container.companies { padding-bottom: 54px; }.second-section.left.left-container.companies p { margin-top: 0; font-size: 16px; }.chk-container { display: block; position: relative; padding-left: 27px; margin-bottom: 12px; cursor: pointer; font-size: 16px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }.chk-container input { position: absolute; opacity: 0; cursor: pointer; height: 0; width: 0; }.chk-container input:checked~.checkmark { background-color: #1D1D25; }.chk-container input:checked~.checkmark { height: 20px; width: 20px; border: none; }.checkmark:after { content: ""; position: absolute; display: none; } /* Show the checkmark when checked */.chk-container input:checked~.checkmark:after { display: block; } /* Style the checkmark/indicator */.chk-container.checkmark:after { left: 7px; top: 3px; width: 4px; height: 10px; border: solid white; border-width: 0 2px 2px 0; -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); transform: rotate(45deg); }.chk-container.checkmark { position: absolute; top: 0; left: 0; height: 20px; width: 20px; background-color: #1D1D25; }.second-section.left.left-container.price { padding-bottom: 54px; }.second-section.left.left-container.price p { margin-top: 0; margin-bottom: 6px; font-size: 16px; }.slider { -webkit-appearance: none; width: 100%; height: 4px; background: #C4C4C4; outline: none; -webkit-transition: .2s; transition: opacity.2s; border-radius: 10px; }.slider:hover { opacity: 1; }.slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 12px; height: 12px; background: #1D1D25; cursor: pointer; border-width: 0; border-radius: 50%; }.slider::-moz-range-thumb { width: 12px; height: 12px; background: #1D1D25; cursor: pointer; border-width: 0; border-radius: 50%; }.second-section.products { display: flex; flex-wrap: wrap; justify-content: space-around; }.second-section.products.box { position: relative; max-width: 260px; width: 260px; background-color: #F7F7F7; margin-bottom: 62px; }.second-section.products.box.image { text-align: center; padding-top: 30px; padding-bottom: 25px; min-height: 157px; display: flex; align-items: center; justify-content: center; }.second-section.products.box.image img { max-width: 200px; }.second-section.products.box.names { text-align: center; font-size: 18px; line-height: 21px; margin-left: 10px; margin-right: 10px; padding-bottom: calc(45% + 10px); }.second-section.products.box.star { text-align: center; padding-bottom: 17px; }.second-section.products.box.price { position: absolute; width: 100%; bottom: 50px; text-align: center; padding-bottom: 21px; color: #1d1d25; font-weight: 700; }.second-section.products.box.price span { font-size: 24px; line-height: 28px; }.second-section.products.box.price span:first-child { font-size: 16px; line-height: 18px; vertical-align: super; }.second-section.pagination-container { display: flex; justify-content: center; margin-top: 15px; }.second-section.pagination-container span, .second-section.pagination-container a { color: #1D1D25; background: none; box-shadow: none; border-width: 0; font-size: 14px; margin-right: 0; }.second-section.pagination-container.active.current { border-radius: 0; border-bottom: 1px solid #1D1D25; }.second-section.pagination-container li.page-link { border-radius: 0; border-bottom: 1px solid #C4C4C4; }.second-section.pagination-container.current.prev, .second-section.pagination-container.current.next, .second-section.pagination-container.page-link.prev, .second-section.pagination-container.page-link.next { display: flex; align-items: center; border-width: 0; }.second-section.pagination-container.prev-image { margin-right: 12px; }.second-section.pagination-container.next-image { margin-left: 12px; } @media screen and (max-width: 1100px) and (min-width: 769px) {.second-section.products.box { width: 49%; /* margin-bottom: 50px; */ } } @media screen and (max-width: 1023px) and (min-width: 769px) {.page-content { padding-top: 80px; width: calc(100% - 5em); } } @media screen and (max-width: 768px) {.text-align { text-align: center; }.page-content { padding-top: 20px; }.page-content.second-section { padding-top: 30px; display: block; width: 90%; margin: 0 auto; }.page-content.second-section.left { padding-right: 0px; padding-top: 45px; margin-left: 0px; }.page-content.second-section.left.left-container { width: 100%; }.second-section.left.left-container.filter { padding-bottom: 35px; }.second-section.products { padding-top: 35px; }.second-section.products.box { width: 48%; margin-bottom: 5px; }.page-content.second-section.title span { font-size: 25px; }.page-content.second-section.container { flex-direction: column; }.page-content.second-section.right { padding-right: 0px; font-size: 14px; }.second-section.products.box.image { height: 100px; padding-top: 20px; padding-bottom: 10px; }.second-section.products.box.image img { max-width: 170px; max-height: 100px; }.second-section.products.box.names { font-size: 13px; line-height: 15px; padding-bottom: 13px; }.second-section.products.box.star { padding-bottom: 11px; }.second-section.products.box.price { padding-bottom: 18px; }.second-section.products.box.price span:nth-child(1) { font-size: 14px; line-height: 18px; }.second-section.products.box.price span:nth-child(2) { font-size: 18px; line-height: 21px; } }
 <section class="second-section"> <div class="left"> <div class="left-container"> <form @submit.prevent="processFilter"> <div class="filter"> <div class="combo-group mobile"> <select> <option v-for="sub in subCategories":key="sub.id"> {{sub.value}} </option> </select> </div> <div class="combo-group mobile"> <select> <option v-for="company in companies":key="company.id"> {{company.name}} </option> </select> </div> </div> <div class="companies desktop"> <p>Categories</p> <label class="chk-container" v-for="sub in subCategories":key="sub.id"> {{sub.value}} <input type="checkbox" id="chk-account-standard" /> <span class="checkmark"></span> </label> </div> <div class="companies desktop"> <p>Companies</p> <label class="chk-container" v-for="company in companies":key="company.id"> {{company.name}} <input type="checkbox" id="chk-account-standard" /> <span class="checkmark"></span> </label> </div> <div class="price"> <p>Price</p> <span id="min-value">10</span><span> - </span><span>1.000</span> <div class="pt-10"> <input type="range" min="10" max="1000" value="1" class="slider" id="priceRang"> </div> </div> <div class="save_filter"> <button type="submit">Filter</button> </div> </form> </div> </div> </section>

So my question is how can I get the input values independently of the number of options loaded from the database?所以我的问题是如何独立于从数据库加载的选项数量获取输入值?

You can use v-model for this, you just need a separate array to store the selected options.您可以为此使用v-model ,您只需要一个单独的数组来存储选定的选项。 Here is an example in the Vue docs.这是 Vue 文档中的一个示例

For your case you'll need to set a value of the inputs element for the field you want to use, then can use v-model to store the selected inputs.对于您的情况,您需要为要使用的字段设置输入元素的value ,然后可以使用v-model来存储选定的输入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM