از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
برنامه های تک صفحه ای با Vue.js و Flask: مدیریت ایالت با Vuex. از اینکه برای پست سوم به من پیوستید متشکریم روی استفاده از Vue.js و Flask برای توسعه وب تمام پشته. موضوع اصلی در این پست خواهد بود روی با استفاده از Vuex برای مدیریت وضعیت در برنامه ما. برای معرفی Vuex، روش بازسازی کامپوننت های Home و Survey را از…
سرفصلهای مطلب
مدیریت دولتی با Vuex
از اینکه برای پست سوم به من پیوستید متشکرم روی استفاده کردن Vue.js
و Flask برای توسعه وب تمام پشته. موضوع اصلی در این پست خواهد بود روی استفاده کردن Vuex
برای مدیریت وضعیت در برنامه ما. معرفی Vuex
، من نشان خواهم داد که چگونه می توان مولفه های Home و Survey را از پست قبلی برای استفاده مجدد تغییر داد Vuex
، و من همچنین توانایی اضافه کردن نظرسنجی های جدید را با استفاده از Vuex
الگو.
کد این پست در یک مخزن است روی من GitHub حساب زیر شعبه پست سوم.
محتوای سری
- راه اندازی و آشنایی با VueJS
- مسیریاب Vue
- مدیریت دولتی با Vuex (تو اینجایی)
- RESTful API با Flask
- ادغام AJAX با REST API
- احراز هویت JWT
- استقرار در یک سرور خصوصی مجازی
معرفی کردن Vuex
Vuex یک کتابخانه مدیریت دولتی متمرکز است که به طور رسمی توسط هسته پشتیبانی می شود Vue.js
تیم توسعه. Vuex
الف را فراهم می کند شار مانند، جریان داده های یک طرفه، الگویی که در پشتیبانی از متوسط تا بزرگ بسیار قدرتمند است Vue.js
برنامه های کاربردی.
پیاده سازی های دیگری از الگوهای مدیریت حالت شار مانند و کتابخانه ها وجود دارد، اما Vuex
برای کار به طور خاص طراحی شده است Vue.js
سیستم واکنش سریع و ساده این امر از طریق یک API به خوبی طراحی شده انجام می شود که منبعی از حقیقت را برای داده های یک برنامه کاربردی به عنوان یک شی تک تنی فراهم می کند. علاوه بر اصل منبع واحد حقیقت، Vuex
همچنین روشهای صریح و قابل ردیابی را برای عملیات ناهمزمان (عملیات)، دسترسیهای قابل استفاده مجدد راحت (گیرنده)، و قابلیتهای تغییر داده (جهش) ارائه میدهد.
برای استفاده Vuex
، ابتدا باید آن را در همان دایرکتوری که حاوی package.json
فایل مانند این:
$ npm install --save vuex
بعد من یک دایرکتوری جدید در داخل پروژه اضافه می کنم src/
دایرکتوری فراخوانی شد store
و یک را اضافه کنید index.js
فایل. این منجر به ساختار پروژه Surve-Spa می شود که اکنون به این شکل است (با نادیده گرفتن دایرکتوری های node_modules، build و config):
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── App.vue
│ ├── api
│ │ └── index.js
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ ├── Header.vue
│ │ ├── Home.vue
│ │ └── Survey.vue
│ ├── main.js
│ ├── router
│ │ └── index.js
│ └── store
│ └── index.js
└── static
└── .gitkeep
درون store/index.js
فایل من با اضافه کردن واردات لازم برای شروع می کنم Vue
و Vuex
اشیاء سپس متصل می شوند Vuex
به Vue
استفاده کردن Vue.use(Vuex)
مشابه کاری که با آن انجام شد vue-router
. پس از این، من چهار شیء جاوا اسکریپت را تعریف می کنم: state
، actions
، mutations
، و getters
.
در انتهای فایل یک شی نهایی تعریف می کنم که نمونه ای از آن است Vuex.Store({})
شی، که تمام اشیاء خرد دیگر را به هم میکشد و سپس صادر میشود.
// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
// single source of data
}
const actions = {
// asynchronous operations
}
const mutations = {
// isolated data mutations
}
const getters = {
// reusable data accessors
}
const store = new Vuex.Store({
state,
actions,
mutations,
getters
})
export default store
خوب، چند لحظه به من فرصت دهید تا معنای آن را توضیح دهم state
، actions
، mutations
، و getters
اشیاء.
را state
شی به عنوان منبع منفرد حقیقت عمل می کند که در آن تمام داده های مهم در سطح برنامه در فروشگاه موجود است. این state
شی حاوی داده های نظرسنجی است که می تواند توسط هر مؤلفه ای که به آنها علاقه دارد، مانند مؤلفه Home، به آنها دسترسی داشته باشد و تغییرات را مشاهده کند.
را actions
شی جایی است که من آنچه را که به عنوان شناخته می شود تعریف می کنم عمل مواد و روش ها. روشهای اقدام به عنوان «ارسال» نامیده میشوند و برای رسیدگی به عملیات ناهمزمان مانند تماسهای AJAX به یک سرویس خارجی یا API استفاده میشوند.
را mutations
شی متدهایی را ارائه می دهد که به آنها “متعهد” می گویند و به عنوان یک و تنها راه برای تغییر وضعیت داده ها در state
هدف – شی. هنگامی که یک جهش انجام می شود، هر مؤلفه ای که به داده های واکنشی در حال حاضر ارجاع می دهد state
شی با مقادیر جدید به روز می شود و باعث می شود UI عناصر خود را به روز کند و دوباره رندر کند.
را getters
شی نیز حاوی متدهایی است، اما در این مورد آنها برای دسترسی به state
داده هایی که از منطقی برای بازگرداندن اطلاعات استفاده می کنند. دریافتکنندهها برای کاهش تکرار کد و ارتقای قابلیت استفاده مجدد در بسیاری از مؤلفهها مفید هستند.
آخرین مرحله لازم برای فعال سازی فروشگاه دوباره به داخل انجام می شود src/main.js
جایی که من import را store
ماژول به تازگی ایجاد شده است. سپس در شی Options که در آن نمونه Vue سطح بالای نمونه است، وارد شده را اضافه می کنم store
به عنوان یک ملک این باید به شکل زیر باشد:
// src/main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
انتقال مولفه خانه به Vuex
من می خواهم شروع به استفاده کنم Vuex
در برنامه Survey با انتقال روشی که نظرسنجی ها در مؤلفه Home بارگذاری می شوند برای استفاده از Vuex
الگو. برای شروع، یک آرایه نظرسنجی خالی را تعریف و مقداردهی اولیه می کنم state
شی در داخل store/index.js
. این مکانی خواهد بود که پس از دریافت درخواست AJAX، تمام داده های نظرسنجی سطح برنامه در آن قرار می گیرند.
const state = {
// single source of data
surveys: ()
}
اکنون که نظرسنجی ها مکانی برای سکونت دارند، باید یک روش اقدام ایجاد کنم، loadSurveys(...)
، که می تواند از مؤلفه Home (یا هر مؤلفه دیگری که به داده های نظرسنجی نیاز دارد) برای رسیدگی به درخواست ناهمزمان به تابع ساختگی AJAX ارسال شود. fetchSurveys()
. برای استفاده fetchSurveys()
من اول نیاز دارم import آن را از api
ماژول را تعریف کنید loadSurveys(...)
روش عمل برای رسیدگی به درخواست
کنشها اغلب همراه با جهشهایی در الگوی انجام درخواستهای AJAX ناهمزمان برای دادهها به سرور و بهروزرسانی صریح فروشگاه کار میکنند. state
شی با داده های واکشی شده هنگامی که جهش انجام شد، بخشهایی از برنامه که از نظرسنجیها استفاده میکنند، بررسیهای بهروز شده را از طریق سیستم واکنشپذیری Vue تشخیص میدهند. در اینجا جهشی که من تعریف می کنم نامیده می شود setSurveys(...)
.
import Vue from 'vue'
import Vuex from 'vuex'
// imports of AJAX functions go here
import { fetchSurveys } from '@/api'
Vue.use(Vuex)
const state = {
// single source of data
surveys: ()
}
const actions = {
// asynchronous operations
loadSurveys(context) {
return fetchSurveys()
.then((response) => context.commit('setSurveys', { surveys: response }))
}
}
const mutations = {
// isolated data mutations
setSurveys(state, payload) {
state.surveys = payload.surveys
}
}
با توجه به اینکه فروشگاه اکنون توانایی واکشی نظرسنجی ها را دارد، می توانم مؤلفه Home را به روز کنم و از فروشگاه برای تغذیه داده های نظرسنجی آن استفاده کنم. برگشت داخل src/components/Home.vue
، من حذف می کنم import از fetchSurveys
تابع:
import { fetchSurveys } from '@/api'
و آن را با یک جایگزین کنید import به Vuex
تابع کمکی فراخوانی شد mapState
.
import { mapState } from 'vuex'
من استفاده خواهم کرد mapState
برای نقشه برداری surveys
آرایه ای که در state
شی به یک ویژگی محاسبه شده نیز نامیده می شود surveys
. mapState
به سادگی تابعی است که ارجاع به یک ویژگی خاص از را حفظ می کند state
هدف – شی (state.surveys
در این مورد)، و اگر آن ویژگی با استفاده از یک جزء جهش یافته باشد mapState
به آن تغییر واکنش نشان می دهد و هر رابط کاربری مرتبط با آن داده را تازه می کند.
در کامپوننت Home من جدید را اضافه کرده ام surveys
دارایی محاسبه شده علاوه بر این، در beforeMount
روش I راه اندازی ارسال از loadSurveys
اقدام ذخیره از آنجایی که در حال حاضر یک ویژگی محاسبه شده به نام وجود دارد surveys
باید موجود را حذف کنم surveys
ویژگی از قسمت داده شی Vue جزء. در واقع، از آنجایی که این تنها ویژگی داده بود، باید کل ویژگی داده را نیز حذف کنم تا همه چیز را مرتب نگه دارم، همانطور که در زیر نشان داده شده است.
<script>
import { mapState } from 'vuex'
export default {
computed: mapState({
surveys: state => state.surveys
}),
beforeMount() {
this.$store.dispatch('loadSurveys')
}
}
</script>
توجه داشته باشید که من می توانم به فروشگاه دسترسی داشته باشم و متد عمل را با سینتکس ارسال کنم this.$store.dispatch(...)
. این باید شبیه روشی باشد که در مقاله قبلی با استفاده از آن به مسیر دسترسی پیدا کردم this.$route
. این به این دلیل است که هر دو vue-router
و Vuex
کتابخانه این اشیاء را به عنوان ویژگی های راحت به نمونه Vue تزریق می کند. من همچنین می توانستم به فروشگاه دسترسی داشته باشم state.surveys
آرایه از درون کامپوننت با استفاده از this.$store.state.surveys
بجای استفاده از mapState
، و همچنین می توانم با استفاده از جهش انجام دهم this.$store.commit
.
در این مرحله باید بتوانم پروژه خود را ذخیره کنم و با درخواست URL، همان عملکرد را در مرورگر خود مشاهده کنم localhost:8080
همانطور که قبلا دیده شد
مهاجرت مؤلفه نظرسنجی
وظیفه بعدی انتقال مولفه Survey برای استفاده است Vuex
‘s فروشگاه برای واکشی نظرسنجی خاص برای شرکت در گرفتن. جریان کلی برای مولفه Survey دسترسی به آن خواهد بود :id
پایه مسیر و سپس از a استفاده کنید Vuex
روش اقدام برای واکشی نظرسنجی توسط آن id
. به جای فراخوانی مستقیم تابع ساختگی AJAX fetchSurvey
همانطور که قبلاً انجام شد، میخواهم آن را به روش دیگری از فروشگاه واگذار کنم که میتواند نظرسنجی واکشی شده را به یک ذخیره کند (یعنی جهش انجام دهد) state
ملکی که نام خواهم برد currentSurvey
.
با شروع در ماژول store/index.js این خط را تغییر می دهم:
import { fetchSurveys } from '@/api'
به
import { fetchSurveys, fetchSurvey } from '@/api'
این به من دسترسی می دهد fetchSurvey
در ماژول فروشگاه من استفاده می کنم fetchSurvey
در یک روش اقدام جدید به نام loadSurvey
که سپس یک جهش را در روش جدید دیگری در داخل انجام می دهد mutations
شی نامیده می شود setCurrentSurvey
.
// src/store/index.js
const actions = {
// asynchronous operations
loadSurveys(context) {
// omitted for brevity
},
loadSurvey(context, { id }) {
return fetchSurvey(id)
.then((response) => context.commit('setSurvey'. { survey: response }))
}
}
در بالا اجرای fetchSurvey
روش عمل مشابه قبلی fetchSurveys
، به جز اینکه یک پارامتر شی اضافی با ویژگی id برای بررسی واکشی به آن داده می شود. برای ساده کردن دسترسی به شناسه از ES2015 استفاده می کنم تخریب شی. هنگامی که اکشن از یک جزء فراخوانی می شود، نحو به شکل زیر خواهد بود: this.$store.dispatch('loadSurvey', { id: 1 })
.
بعد من اضافه می کنم currentSurvey
دارایی به state
هدف – شی. در نهایت، من یک جهش به نام تعریف می کنم setSurvey
در mutations
شی، که a اضافه می کند choice
برای هر سوال، انتخاب انتخاب شده نظرسنجی را نگه دارید و مقدار آن را تنظیم کنید currentSurvey
.
const state = {
// single source of data
surveys: (),
currentSurvey: {}
}
const actions = { // omitted for brevity }
const mutations = {
// isolated data mutations
setSurveys(state, payload) {
state.surveys = payload.surveys
},
setSurvey(state, payload) {
const nQuestions = payload.survey.questions.length
for (let i = 0; i < nQuestions; i++) {
payload.survey.questions(i).choice = null
}
state.currentSurvey = payload.survey
}
}
در Survey.vue
فایل کامپوننت، من آن را به روز می کنم beforeMount
روش ارسال loadSurvey
اقدام و نقشه state.currentSurvey
به یک ویژگی محاسبه شده به نام survey
. پس از آن می توانم موجود را حذف کنم survey
ویژگی داده
<script>
import { saveSurveyResponse } from '@/api'
export default {
data() {
return {
currentQuestion: 0
}
},
beforeMount() {
this.$store.dispatch('loadSurvey', { id: parseInt(this.$route.params.id) })
},
methods: {
// omitted for brevity
},
computed: {
surveyComplete() {
// omitted for brevity
},
survey() {
return this.$store.state.currentSurvey
}
}
}
</script>
ذخیره فایل های پروژه و بازخوانی مرورگر برای درخواست URL localhost:8080/#/surveys/2
دوباره همان UI مانند شکل زیر را به من می دهد.
با این حال، هنوز کمی مشکل وجود دارد. در کد قالب که انتخاب های هر سوالی را که استفاده می کنم نمایش می دهد v-model="question.choice"
برای ردیابی تغییرات زمانی که کاربر انتخابی را انتخاب می کند.
<div v-for="choice in question.choices" v-bind:key="choice.id">
<label class="radio">
<input type="radio" v-model="question.choice" :value="choice.id">
{{ choice.text }}
</label>
</div>
این منجر به تغییراتی در question.choice
ارزشی که در فروشگاه ذکر شده است state.currentQuestion
ویژگی. این نمونه ای از تغییر نادرست داده های ذخیره خارج از یک جهش است. را vuex مستندات توصیه می کنند که هرگونه تغییر در داده های وضعیت فروشگاه منحصراً با استفاده از جهش انجام شود. ممکن است بپرسید چگونه می توانم استفاده کنم؟ v-model
در ترکیب با یک عنصر ورودی که توسط داده های منبع از a هدایت می شود Vuex
فروشگاه؟
پاسخ به این، استفاده از یک نسخه کمی پیشرفته تر از یک ویژگی محاسبه شده است که شامل یک جفت تعریف شده است get
و set
روش های درون آن این فراهم می کند v-model
مکانیزمی برای استفاده از اتصال داده دو طرفه بین UI و شی Vue جزء. به این ترتیب ویژگی محاسبه شده به صراحت بر تعاملات با داده های فروشگاه کنترل می کند. در کد قالب باید جایگزین کنم v-model="question.choice"
با ویژگی جدید محاسبه شده مانند این v-model="selectedChoice"
. در زیر پیاده سازی ویژگی محاسبه شده است selectedChoice
.
computed: {
surveyComplete() {
// omitted for brevity
},
survey() {
return this.$store.state.currentSurvey
},
selectedChoice: {
get() {
const question = this.survey.questions(this.currentQuestion)
return question.choice
},
set(value) {
const question = this.survey.questions(this.currentQuestion)
this.$store.commit('setChoice', { questionId: question.id, choice: value })
}
}
}
توجه داشته باشید که در این پیاده سازی selectedChoice
در واقع یک ویژگی شی به جای تابعی مانند بقیه است. را get
تابع در ارتباط با currentQuestion
ویژگی داده برای برگرداندن choice
ارزش سوال در حال مشاهده را set(value)
بخش مقدار جدیدی را دریافت می کند که از آن تغذیه می شود v-model
‘s داده های 2 طرفه متصل می شود و یک جهش ذخیره ای به نام را مرتکب می شود setChoice
. را setChoice
جهش به یک بار شیء حاوی id
از سوال به همراه جدید به روز شود value
.
من اضافه می کنم setChoice
جهش به ماژول فروشگاه به این صورت:
const mutations = {
setSurveys(state, payload) {
state.surveys = payload.surveys
},
setSurvey(state, payload) {
// omitted for brevity
},
setChoice(state, payload) {
const { questionId, choice } = payload
const nQuestions = state.currentSurvey.questions.length
for (let i = 0; i < nQuestions; i++) {
if (state.currentSurvey.questions(i).id === questionId) {
state.currentSurvey.questions(i).choice = choice
break
}
}
}
}
آخرین چیزی که باید در مولفه Survey مهاجرت کرد، ذخیره گزینه های پاسخ نظرسنجی است. برای شروع، در Survey.vue
، باید آن را حذف کنم import از saveSurveyResponse
عملکرد AJAX
import { saveSurveyResponse } from '@/api'
و آن را به عنوان یک اضافه کنید import در ماژول src/store/index.js به این صورت:
import { fetchSurveys, fetchSurvey, saveSurveyResponse } from '@/api'
در حال حاضر پایین در actions
متدهای ماژول store/index.js باید روش جدیدی به نام اضافه کنم addSurveyResponse
، که تماس خواهد گرفت saveSurveyResponse
عملکرد AJAX و در نهایت آن را به سرور ادامه می دهد.
const actions = {
loadSurveys(context) {
// omitted for brevity
},
loadSurvey(context, { id }) {
// omitted for brevity
},
addSurveyResponse(context) {
return saveSurveyResponse(context.state.currentSurvey)
}
}
برگشت در Survey.vue
فایل کامپوننت، باید آن را به روز کنم handleSubmit
روشی برای ارسال این متد عمل به جای فراخوانی مستقیم saveSurveyResponse
مانند:
methods: {
goToNextQuestion() {
// omitted for brevity
},
goToPreviousQuestion() {
// omitted for brevity
},
handleSubmit() {
this.$store.dispatch('addSurveyResponse')
.then(() => this.$router.push('/'))
}
}
افزودن قابلیت ایجاد نظرسنجی جدید
باقیمانده این پست به ایجاد قابلیت ایجاد یک نظرسنجی جدید با نام، سؤالات و انتخابهای هر سؤال اختصاص خواهد یافت.
برای شروع باید یک فایل کامپوننت به نام اضافه کنم NewSurvey.vue
داخل دایرکتوری کامپوننت ها بعد من می خواهم import و یک مسیر جدید به آن اضافه کنید router/index.js
ماژول مانند این:
// other import omitted for brevity
import NewSurvey from '@/components/NewSurvey'
Vue.use(Router)
export default new Router({
routes: (
{
path: '/',
name: 'Home',
component: Home
}, {
path: '/surveys/:id',
name: 'Survey',
component: Survey
}, {
path: '/surveys',
name: 'NewSurvey',
component: NewSurvey
}
)
})
درون Header.vue
فایل، من باید یک پیوند ناو اضافه کنم تا بتوانم به نمای ایجاد حرکت کنم.
<template>
<nav class="navbar is-light" role="navigation" aria-label="main navigation">
<div class="navbar-menu">
<div class="navbar-start">
<router-link to="/" class="navbar-item">
Home
</router-link>
<router-link to="/surveys" class="navbar-item">
Create Survey
</router-link>
</div>
</div>
</nav>
</template>
در حال حاضر در NewSurvey.vue
کامپوننت، من ساختار اصلی رابط کاربری ایجاد نظرسنجی را داربست خواهم کرد.
<template>
<div>
<section class="hero is-primary">
<div class="hero-body">
<div class="container has-text-centered">
<h2 class="title">{{ name }}</h2>
</div>
</div>
</section>
<section class="section">
<div class="container">
<div class="tabs is-centered is-fullwidth is-large">
<ul>
<li :class="{'is-active': step == 'name'}" @click="step = 'name'">
<a>Name</a>
</li>
<li :class="{'is-active': step == 'questions'}" @click="step = 'questions'">
<a>Questions</a>
</li>
<li :class="{'is-active': step == 'review'}" @click="step = 'review'">
<a>Review</a>
</li>
</ul>
</div>
<div class="columns">
<div class="column is-half is-offset-one-quarter">
<div class="name" v-show="step === 'name'">
<h2 class='is-large'>Add name</h2>
</div>
<div class="questions" v-show="step === 'questions'">
<h2>Add Questions</h2>
</div>
<div class="review" v-show="step === 'review'">
<h2>Review and Submit</h2>
</div>
</div>
</div>
</div>
</section>
</div>
</template>
<script>
export default {
data() {
return {
step: 'name'
}
}
}
</script>
<style></style>
همانطور که در تصویر بالا می بینید، سه تب وجود دارد که نمایش اجزای رابط کاربری را برای اضافه کردن نام، سؤالات و بررسی قبل از ذخیره کردن فعال می کند.
عملکردی که باعث تعامل این می شود page بر اساس دیکته شده است روی ارزش a step
ویژگی داده که تعیین می کند کدام برگه باید فعال باشد. step
به صورت پیشفرض روی برگه «نام» قرار میگیرد، اما با کلیک کاربر بهروزرسانی میشود روی یکی از برگه های دیگر نه تنها ارزش step
تعیین کنید کدام برگه باید داشته باشد is-active
کلاس، اما نمایش و پنهان کردن آن را نیز هدایت می کند divs
که رابط کاربری را برای افزودن نام، سؤال و بررسی قبل از ارسال ارائه می دهد.
من با نام UI شروع می کنم div
که به سادگی حاوی یک ورودی متنی است که به a گره خورده است name
ویژگی داده از طریق v-model
، مانند:
بخش قالب
<div class="name" v-show="step === 'name'">
<div class="field">
<label class="label" for="name">Survey name:</label>
<div class="control">
<input type="text" class="input is-large" id="name" v-model="name">
</div>
</div>
</div>
بخش اسکریپت
data() {
return {
step: 'name',
name: ''
}
}
UI سوالات و پاسخ ها کمی بیشتر درگیر خواهد شد. برای نگه داشتن NewSurvey
جزء سازماندهی شده و کاهش پیچیدگی را اضافه می کنم NewQuestion.vue
جزء فایل برای رسیدگی به رابط کاربری و رفتار لازم برای افزودن سؤالات جدید به همراه تعداد متغیری از پاسخ ها.
همچنین باید توجه داشته باشم که برای مؤلفههای NewSurvey و NewQuestion از حالت سطح مؤلفه برای جدا کردن فروشگاه از دادههای نظرسنجی جدید واسطه استفاده میکنم تا زمانی که کاربر نظرسنجی جدید را ارسال کند. پس از ارسال، من شرکت خواهم کرد Vuex
ذخیره و الگوی مربوط به ارسال یک اقدام برای ارسال نظرسنجی جدید به سرور و سپس به مؤلفه Home تغییر مسیر دهید. سپس مؤلفه Home میتواند همه نظرسنجیها از جمله نظرسنجی جدید را واکشی کند.
در NewQuestion.vue
فایل، من اکنون کد زیر را دارم:
<template>
<div>
<div class="field">
<label class="label is-large">Question</label>
<div class="control">
<input type="text" class="input is-large" v-model="question">
</div>
</div>
<div class="field">
<div class="control">
<a class="button is-large is-info" @click="addChoice">
<span class="icon is-small">
<i class="fa fa-plus-square-o fa-align-left" aria-hidden="true"></i>
</span>
<span>Add choice</span>
</a>
<a class="button is-large is-primary @click="saveQuestion">
<span class="icon is-small">
<i class="fa fa-check"></i>
</span>
<span>Save</span>
</a>
</div>
</div>
<h2 class="label is-large" v-show="choices.length > 0">Question Choices</h2>
<div class="field has-addons" v-for="(choice, idx) in choices" v-bind:key="idx">
<div class="control choice">
<input type="text" class="input is-large" v-model="choices(idx)">
</div>
<div class="control">
<a class="button is-large">
<span class="icon is-small" @click.stop="removeChoice(choice)">
<i class="fa fa-times" aria-hidden="true"></i>
</span>
</a>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
question: '',
choices: ()
}
},
methods: {
removeChoice(choice) {
const idx = this.choices.findIndex(c => c === choice)
this.choices.splice(idx, 1)
},
saveQuestion() {
this.$emit('questionComplete', {
question: this.question,
choices: this.choices.filter(c => !!c)
})
this.question = ''
this.choices = ()
},
addChoice() {
this.choices.push('')
}
}
}
</script>
<style>
.choice {
width: 90%;
}
</style>
بیشتر ویژگی ها قبلاً مورد بحث قرار گرفته اند، بنابراین من فقط به طور خلاصه آنها را بررسی می کنم. برای شروع، من یک question
ویژگی داده که از طریق به ورودی متنی متصل می شود v-model="question"
ارائه اتصال داده دو طرفه بین ویژگی داده question
و عنصر ورودی UI.
در زیر ورودی متن سوال دو دکمه وجود دارد. یکی از دکمه ها برای افزودن یک انتخاب است و شامل شنونده رویداد است @click="addChoice"
که یک رشته خالی را روی choices
آرایه. را choices
آرایه برای هدایت نمایش ورودی های متن انتخابی استفاده می شود که هر کدام به عنصر مربوطه خود گره خورده اند choices
آرایه از طریق v-model="choices(idx)"
. هر ورودی متن انتخابی با یک دکمه جفت می شود که به کاربر اجازه می دهد آن را به دلیل حضور شنونده رویداد کلیک حذف کند. @click="removeChoice(choice)"
.
آخرین قطعه UI در مؤلفه NewQuestion که باید مورد بحث قرار گیرد، دکمه ذخیره است. هنگامی که کاربر سؤال خود را اضافه کرد و تعداد گزینه های مورد نظر خود را اضافه کرد، می تواند برای ذخیره سؤال روی آن کلیک کند. این کار از طریق شنونده کلیک انجام می شود @click="saveQuestion"
.
با این حال، در داخل saveQuestion
روش من موضوع جدیدی را معرفی کرده ام. توجه داشته باشید که من از روش دیگری متصل به نمونه Vue کامپوننت استفاده می کنم. این است this.$emit(...)
روش ساطع کننده رویداد در فراخوانی این، من در حال پخش به مؤلفه اصلی، NewSurvey، رویداد نامیده می شود questionComplete
و همراه با آن یک شی محموله با question
و choices
.
برگشت در NewSurvey.vue
فایل، من می خواهم import این NewQuestion
کامپوننت و آن را در نمونه Vue کامپوننت به این صورت ثبت کنید:
<script>
import NewQuestion from '@/components/NewQuestion'
export default {
components: { NewQuestion },
data() {
return {
step: 'name',
name: ''
}
}
}
</script>
سپس می توانم آن را به عنوان یک عنصر مؤلفه مانند این در قالب قرار دهم:
<div class="questions" v-show="step === 'questions'">
<new-question v-روی:questionComplete="appendQuestion"/>
</div>
توجه داشته باشید که من از آن استفاده کرده ام v-روی
دستورالعمل گوش دادن به questionComplete
رویدادی که باید از مؤلفه NewQuestion ساطع شود و یک فراخوان از آن ثبت شود appendQuestion
. این همان مفهومی است که ما با آن دیدیم @click="someCallbackFunction"
شنونده رویداد، اما این بار برای یک رویداد سفارشی است. اتفاقا من میتونستم از کوتاهتر استفاده کنم @questionComplete="appendQuestion"
نحو، اما من فکر کردم که تنوعی در آن ایجاد کنم، و همچنین به این صورت واضح تر است.
نکته منطقی بعدی اضافه کردن آن خواهد بود appendQuestion
روش به NewSurvey
جزء همراه با الف questions
ویژگی داده برای حفظ مجموعه سوالات و پاسخ های تولید شده در NewQuestion
جزء و ساطع شده به NewSurvey
.
export default {
components: { NewQuestion },
data() {
return {
step: 'name',
name: '',
question: ()
}
},
methods: {
appendQuestion(newQuestion) {
this.questions.push(newQuestion)
}
}
}
اکنون می توانم با مرورگر در URL ذخیره و بازخوانی کنم localhost:8080/#/surveys
سپس کلیک کنید روی برگه سؤالات، متن سؤال و چند گزینه را مانند شکل زیر اضافه کنید.
آخرین برگه ای که باید تکمیل شود، تب Review است. این page سوالات و گزینه ها را لیست می کند و همچنین امکان حذف آنها را به کاربر ارائه می دهد. اگر کاربر راضی باشد، میتواند نظرسنجی را ارسال کند و برنامه به مؤلفه Home هدایت میشود.
بخش قالب کد برای UI بررسی به شرح زیر است:
<div class="review" v-show="step === 'review'">
<ul>
<li class="question" v-for="(question, qIdx) in questions" :key="`question-${qIdx}`">
<div class="title">
{{ question.question }}
<span class="icon is-medium is-pulled-right delete-question"
@click.stop="removeQuestion(question)">
<i class="fa fa-times" aria-hidden="true"></i>
</span>
</div>
<ul>
<li v-for="(choice , cIdx) in question.choices" :key="`choice-${cIdx}`">
{{ cIdx + 1 }}. {{ choice }}
</li>
</ul>
</li>
</ul>
<div class="control">
<a class="button is-large is-primary" @click="submitSurvey">Submit</a>
</div>
</div>
بخش اسکریپت اکنون فقط باید با افزودن آن به روز شود removeQuestion
و submitSurvey
روش هایی برای رسیدگی به شنوندگان رویداد کلیک مربوطه خود.
methods: {
appendQuestion(newQuestion) {
this.questions.push(newQuestion)
},
removeQuestion(question) {
const idx = this.questions.findIndex(q => q.question === question.question)
this.questions.splice(idx, 1)
},
submitSurvey() {
this.$store.dispatch('submitNewSurvey', {
name: this.name,
questions: this.questions
}).then(() => this.$router.push('/'))
}
}
را removeQuestion(question)
روش سوال را از روی حذف می کند questions
آرایه ای در ویژگی داده که به صورت واکنشی لیست سوالات تشکیل دهنده رابط کاربری بالا را به روز می کند. را submitSurvey
متد یک روش اقدام به زودی اضافه می کند submitNewSurvey
و محتوای نظرسنجی جدید را به آن ارسال می کند و سپس از کامپوننت استفاده می کند this.$router.push(...)
برای تغییر مسیر برنامه به مؤلفه Home.
اکنون تنها کاری که باید انجام داد ایجاد آن است submitNewSurvey
روش عمل و تابع ساختگی AJAX مربوط به ارسال جعلی به سرور. در فروشگاه actions
شی من موارد زیر را اضافه می کنم.
const actions = {
// asynchronous operations
loadSurveys(context) {
return fetchSurveys()
.then((response) => context.commit('setSurveys', { surveys: response }))
},
loadSurvey(context, { id }) {
return fetchSurvey(id)
.then((response) => context.commit('setSurvey', { survey: response }))
},
addSurveyResponse(context) {
return saveSurveyResponse(context.state.currentSurvey)
},
submitNewSurvey(context, survey) {
return postNewSurvey(survey)
}
}
در نهایت، در api/index.js
ماژول را اضافه می کنم postNewSurvey(survey)
عملکرد AJAX برای تمسخر POST به سرور.
export function postNewSurvey(survey) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Saving survey ...', survey)
resolve()
}, 300)
})
}
من تمام فایل های پروژه ام را ذخیره می کنم و URL را درخواست می کنم localhost:8080/#/surveys
. سپس یک نام، چند سوال با انتخاب اضافه کنید و مکث کنید روی در برگه بررسی، رابط کاربری زیر را می بینم:
منابع
می خواهید در مورد آن بیشتر بدانید Vue.js
و ساختن برنامه های وب جلویی؟ سعی کنید برخی از منابع زیر را برای بررسی عمیقتر در این چارچوب ظاهری بررسی کنید:
نتیجه
در طول این پست سعی کردم آنچه را که فکر می کنم مهمترین جنبه های یک موضوع نسبتاً بزرگ است پوشش دهم. Vuex
. Vuex
یک افزودنی بسیار قدرتمند به a است Vue.js
پروژه ای که به توسعه دهنده الگویی بصری می دهد که سازماندهی و استحکام تک تک داده محور متوسط تا بزرگ را بهبود می بخشد. page برنامه های کاربردی.
مثل همیشه، ممنون که خواندید و از نظر دادن یا انتقاد در زیر خجالت نکشید.
منتشر شده در 1403-01-27 03:49:03