【问题标题】:Cannot pass an object to a new route using props无法使用道具将对象传递给新路由
【发布时间】:2021-06-10 09:58:30
【问题描述】:

我正在开展一个项目,用户填写测验并且需要将结果传递到新页面。测验具有测验组件和测验完成组件,用户可以在其中进入结果页面。我已经能够将测验答案传递给 QuizFinished,但问题在于将 QuizFinished 的答案传递给 QuizResults。我从here 复制了一些代码,这些代码来自this stackoverflow 问题,但代码不起作用。 我在这里错过了什么吗? 任何帮助将不胜感激。

测验.vue

<template>
  <div class="quiz-background py-5" id="mood-finder">
    <b-container class="text-center">
      <h1 class="">Mood finder</h1>
      <component
 <!-- This event is triggered when a question is answered in Question.vue, that works -->
        v-on:click="_answerQuestion($event)"
<!-- Going from the startpage to the quiz -->
        v-on:start="this.startQuiz"
        v-bind:is="component"
<!-- Binds the answers to be read in QuizResult -->
        :answers="answers"
        ref="question"
      />
      <b-row class="d-flex justify-content-center">
        <b-col cols="12" md="8" class="pt-3">
<!-- A progress bar -->
          <b-progress
            variant="primary"
            aria-label="Voortgang van de Moodfinder"
            :value="progress"
            :max="maxProgress"
          ></b-progress>
        </b-col>
      </b-row>
    </b-container>
  </div>
</template>
<script>
import quizStart from "./QuizStart.vue";
import question from "./Question";
import strawberry from "../assets/strawberry.webp";
import banana from "../assets/banana.webp";
import quizFinished from "./QuizFinished.vue";
export default {
  name: "app",
  components: {
    quizStart,
    question,
    quizFinished,
  },
  data() {
    return {
      questionIndex: 0,
<!--The array with the answers. It is put in an object to circumvent the array limitation by Vue: https://github.com/vuejs/vue/issues/1798 -->
      answers: {array: []},
      component: "quizStart",
      strawberry: strawberry,
      banana: banana,
      progress: 0,
      maxProgress: 99,
    };
  },
  methods: {
    /**
     * @description
     * saved pressed answer text in answers array
     */
    _answerQuestion(chosenItem) {
      this.answers.array.push(chosenItem);
      this.switchQuestion();
    },
    startQuiz(){
      this.component= "question"
    },
    /**
     * @description switches the questions when the user performs an action in the quiz
     * it swaps out the quiz images, text and quiz question for each question.
     */
    switchQuestion() {
      /**
       * questionIndex stands for the question the user would like to go to.
       * So e.g questionIndex = 1 is going to the second question (counting from 0)
       */
      this.questionIndex++;
      switch (this.questionIndex) {
        case 0:
          this.progress = 0;
        break;
        // //For question 1, see Question.Vue data field
        case 1:
          this.$refs.question.setQuestion("Question 2");
          this.$refs.question.setItems(
            { name: "strawberry", variety: "sweet" },
            { name: "strawberry", variety: "sweet" },
            { name: "strawberry", variety: "sweet" },
            { name: "strawberry", variety: "sweet" }
          );
          this.$refs.question.setImage(
            this.strawberry,
            this.strawberry,
            this.strawberry,
            this.strawberry
          );
          this.progress = 33;
          break;
        case 2:
          console.log(this.questionIndex)
          this.$refs.question.setQuestion("Question 3");
          this.$refs.question.setItems(
            { name: "banana", variety: "sweet" },
            { name: "banana", variety: "sweet" },
            { name: "banana", variety: "sweet" },
            { name: "banana", variety: "sweet" }
          );
          this.$refs.question.setImage(
            this.banana,
            this.banana,
            this.banana,
            this.banana
          );
          this.progress = 66;
          break;
        case 3:
          this.progress = 99;
       //Goes to the quizFinished component
          this.component = quizFinished;
      }
    },
  },
};
</script>

//removed the styles

QuizFinished.vue:

<template>
  <b-row class="d-flex justify-content-center py-3">
    <b-col class="col-6 col-lg-2">
      <p class="text-white">
        De Mood finder is gemaakt. Je resultaten staan klaar!
      </p>
      <!-- <router-link :to="{ path: '/results/', params: { answers: answers } }"
        ><button class="btn btn-primary" type="button">
          Verder naar resultaten
        </button></router-link
      > -->
      <br />
      <router-link :to="{ name: 'results', params: { params: answers} }"
        >Go to results</router-link>
<!-- For testing purposes, the answers are shown here as: { "array": [{object1} etc.]} -->
      {{ answers }}
    </b-col>
  </b-row>
</template>
<script>
export default {
  name: "quizFinished",
  props: {
//For reasoning behind type: Object, see previous codeblock
    answers: { type: Object, required: false },
  },
};
</script>

//removed styles


测验结果.vue


<!-- Html here -->

<script>
export default {
   props: {
    params: { type: Object, required: false },
  },
  mounted() {
//returns undefined, adding a html object like this: {{params}} returns nothing
    console.log(this.params);
  }
};
</script>

//removed styles

main.js:


import Vue from 'vue';
import App from './App.vue';
import VueRouter from 'vue-router';
import './registerServiceWorker';
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue';
import 'bootstrap-vue/dist/bootstrap-vue.css';
import '../src/scss/bootstrap.css';
// Import for fontAwesome : svg-core, brand icons and vue
import { library } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { fab } from '@fortawesome/free-brands-svg-icons';
import VueMeta from 'vue-meta';

library.add(fab);
// fontawesome component neccesary to call
Vue.component('font-awesome-icon', FontAwesomeIcon, fab);
// Make BootstrapVue available throughout your project
Vue.component('font-awesome-icon', FontAwesomeIcon, fab);
Vue.use(BootstrapVue);
Vue.use(IconsPlugin);
Vue.use(VueRouter);
Vue.use(VueMeta);

import results from './components/pages/Results';
import index from './components/pages/Index';
import pageNotFound from './components/pages/PageNotFound';
import webshop from './components/pages/Webshop';

const resultsRoute = { path: '/results', name: 'results', component: results, props: true, };
const indexRoute = { path: '/', name: 'index', component: index };
const pageNotFoundRoute = { path: '*', name: 'pageNotFound', component: pageNotFound };
const webshopRoute = { path: '/webshop', name: 'webshop', component: webshop };

const routes = [resultsRoute, indexRoute, pageNotFoundRoute, webshopRoute];

const router = new VueRouter({
    routes,
    mode: 'history',
});

Vue.config.productionTip = false;

new Vue({
    router,
    render: function(h) {
        return h(App);
    },
}).$mount('#app');

【问题讨论】:

    标签: vuejs2


    【解决方案1】:

    这是一个使用 VueRouter 显示测验的非常快速的 sn-p:

    const QuizStart = {
      template: `
        <div><router-link :to="'/question/0'">START</router-link></div>
      `
    }
    
    const QuizQuestion = {
      props: ['qidx', 'questions'],
      computed: {
        question() {
          return this.questions[this.qidx]
        },
      },
      methods: {
        setAnswer(val) {
          this.$emit('set-answer', {
            id: this.qidx,
            answer: val
          })
          let next = ''
          if (Number(this.qidx) < this.questions.length - 1) {
            next = `/question/${ Number(this.qidx) + 1 }`
          } else {
            next = '/result'
          }
          this.$router.push(next)
        },
      },
      template: `
        <div>
          {{ question.text }}:<br />
          <button @click="() => setAnswer(1)">YES</button> | <button @click="() => setAnswer(-1)">NO</button>
        </div>
      `
    }
    
    const QuizResult = {
      props: ['questions'],
      computed: {
        computedResult() {
          return this.questions.reduce((a, c) => a + c.answer, 0)
        }
      },
      template: `
        <div>
          Your score is {{ computedResult }}
        </div>
      `
    }
    
    const routes = [{
        path: '/',
        component: QuizStart
      },
      {
        path: '/question/:qidx',
        component: QuizQuestion,
        props: true
      },
      {
        path: '/result',
        component: QuizResult
      },
    ]
    
    const router = new VueRouter({
      routes // short for `routes: routes`
    })
    
    new Vue({
      el: "#app",
      components: {
        QuizStart,
        QuizQuestion,
        QuizResult,
      },
      router,
      data() {
        return {
          questions: [{
              text: 'Is this the first question?',
              answer: null,
            },
            {
              text: 'Is this the second question?',
              answer: null,
            },
            {
              text: 'Is this the third question?',
              answer: null,
            },
          ],
        }
      },
      methods: {
        setAnswer({
          id,
          answer
        }) {
          this.questions[id].answer = answer
        },
      },
      template: `
        <div>
          <div>
            QUESTIONS STATE: {{ questions }}
          </div>
          <hr />
          <router-view
            :questions="questions"
            @set-answer="(data) => setAnswer(data)"
          ></router-view>
        </div>
      `
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <div id="app"></div>

    你可以看到

    • 在一个地方跟踪整个测验状态:问题组件除了显示问题并将答案发送回父级以更新状态外什么都不做;
    • 问题是从父母那里传下来的; route 参数 (:qidx) 用于选择要显示的问题;
    • 当到达最后一题时,下一步自动进入结果页面;但是,由于router-view 中的所有页面都会收到问题的状态,因此可以根据您可能需要的任何计算规则轻松计算结果。

    我希望这可以帮助您“顺利进行测验流程”:)

    【讨论】:

    • 我了解您的代码如何提供帮助,但在将其作为索引页面的一部分加载时遇到问题。这个测验是主页上的一个组件,这段代码是一个全新的路由器视图。您能否指出一些可能对此有所帮助的文档?
    • @Stijn 抱歉,但我无法确定下一步要添加哪些内容可能适用于您的设置。它可能是children routesnamed routes 等。或者,在没有路由或使用预制测验组件/解决方案的情况下这样做会更容易。
    【解决方案2】:

    我最终做的是像这样直接推送到路由器:

    在按钮中:

    v-on:click="toResults()"
       
    

    在方法中:

             toResults() {
              this.$router.push({
                name: "resultsRoute",
                params: {
                  items: this.answers,
                }
    

    然后我就可以像这样拿到另一边的物品:

    vm.$route.params.items
    

    【讨论】:

      猜你喜欢
      • 2019-06-30
      • 2019-09-04
      • 2022-12-17
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 2019-12-15
      • 2018-11-03
      • 2023-03-31
      相关资源
      最近更新 更多