Vue:在另一个页面上显示来自表单提交的响应
Posted
技术标签:
【中文标题】Vue:在另一个页面上显示来自表单提交的响应【英文标题】:Vue: display response from form submit on another page 【发布时间】:2020-09-11 06:38:54 【问题描述】:我在vue
中有一个<form>
。我将该表单发送到服务器,获取 JSON 响应,然后将其打印到控制台。它工作正常。
但是,我需要获取该 JSON 响应并将其显示在另一个页面上。例如,我有两个 .vue
文件:GetAnimal.vue
具有表单并从 API 检索动物数据,DisplayAnimal.vue
显示动物数据。我需要将响应动物数据从GetAnimal.vue
定向到DisplayAnimal.vue
。
GetAnimal.vue:
<template>
<form v-on:submit.prevent="getAnimal()">
<textarea v-model = "animal"
name = "animal" type="animal" id = "animal"
placeholder="Enter your animal here">
</textarea>
<button class = "custom-button dark-button"
type="submit">Get animal</button>
</form>
</template>
<script>
import axios from 'axios';
export default
name: 'App',
data: function()
return
info: '',
animal: ''
,
methods:
getAnimal: function()
axios
.get('http://localhost:8088/animalsapi?animal=' + this.animal)
.then(response => (this.info = response.data));
console.log(this.info);
</script>
回复: 检索带有动物数据的 JSON,如下所示:
"fur-color": "yellow",
"population": 51000,
"isExtinct": false,
"isDomesticated": true
我现在想将该 JSON 提供给位于 /viewanimal
端点的 DisplayAnimal.vue
:
DisplayAnimal.vue:
<template>
<div>
<p>Animal name: animal</p>
<p>Fur color: furColor</p>
<p>Population: population</p>
<p>Is extinct: isExtinct</p>
<p>Is domesticated: isDomesticated</p>
</div>
</template>
我该怎么做?我知道我可以通过this.$router.push( path );
重定向,但我只将它用于导航,而这里需要传递 JSON 响应。这甚至是解决此问题的正确/良好做法吗?
编辑:
我试过了:
在 GetAnimal.vue 我添加了这个数据:
data: function()
return
animal:
name: 'Cat',
furColor: 'red',
population: '10000',
isExtinct: false,
isDomesticated: true
在 DisplayAnimal.vue 中:
<script>
export default
props:
animal:
name:
type: String
,
furColor:
type: String
,
population: String,
isExtinct: String,
isDomesticated: String
</script>
在 GetAnimal.vue 我添加了这个:
methods:
animals: function()
alert("animals");
this.$router.push(name: 'viewanimal',
query: animal: JSON.stringify(this.animal));
,
尝试使用显示组件显示该测试动物。但是它不起作用 - 我得到一个空页面。
【问题讨论】:
像这样保存数据的正确方法是使用 Vuex 状态 为什么不$router.push
将表单输入(作为查询)到接收组件并在那里调用 API?否则,我必须同意这里的其他人,这最好用 Vuex 来完成。
如果您想要快速解决方案,您可以localStorage.setItem("animal", JSON.stringify(yourdata));
然后您可以使用var data = JSON.parse(localStorage.getItem("animal"));
检索,最后使用localStorage.removeItem("animal");
删除它,您可以在developer.mozilla.org/en-US/docs/Web/API/Window/localStorage 阅读有关localStorage 的信息。正确的解决方案是您开始使用 vuex,然后您可以轻松地在路由器组件之间共享数据,vuex 可能听起来很吓人,但这是您在 SPA 中获得的最佳选择。
@mentorgashi 它如何同时工作?有几个用户同时用不同的动物填写表格并想查看他们动物的数据? localStorage
不是作为全局/静态变量工作,只有 1 个副本/值在各处共享吗?
你可以从这里开始 vuex 的基础知识 vuemastery.com/courses/mastering-vuex/… 非常好的和透彻的解释。
【参考方案1】:
首先创建一个名为 services 的第二个文件夹,并为您的 axios 调用创建 service.js - 良好的实践和更简洁的代码。 第二次使用vuex。这种数据最好配合vuex使用。
据我了解 GetAnimal.vue 是父组件,您希望在子组件 DisplayAnimal.vue 中显示它。 如果是这样,你想看看这是否有效,只需使用道具。 您还可以使用 $emit() 将孩子的相同信息或任何其他信息发送回父母。 强烈建议使用 vuex 来管理状态
【讨论】:
你能显示一些代码吗?不,GetAnimal.vue
目前与DisplayAnimal.vue
没有任何关联——我拥有的代码就是我发布的代码。为什么会是父母?我正在考虑 GetAnimal.vue
既是控制器又是模型的 MVC 模型:表单获取用户的输入并更新模型(动物信息:this.info
)。现在只需将该信息传递给视图 DisplayAnimal.vue
。
我来自 Java,在 Java 应用程序中我没有看到扩展模型/控制类的视图类 - 这种关系通常是一种组合而不是继承。
那你想做什么?为了在 vue 中显示从一个组件到另一个组件的数据,使用 vuex 或使用 props 传递数据(从父级到子级,或者您可以将其称为兄弟姐妹),即使使用道具也是如此。【参考方案2】:
Vue.component('product',
props:
message:
type:String,
required:true,
default:'Hi.'
,
template:`<div>message</div>`,
data()...
)
//html in the other component you axios call is in this component //<product meesage="hello"></product>
【讨论】:
您在 vuejs 中总共有 3 个选项,这取决于您的需要 1-使用道具从父级到子级共享数据,2-发出自定义事件以从子级到父级共享数据,3 - 使用 Vuex 创建应用级共享状态。 我如何将message
值传递给该组件?我已经阅读过关于 props 的内容,但我不明白如何将 props 值从 GetAnimal.vue
分配给 DisplayAnimal.vue
。
您写“props”的组件是接收组件,如上所示,您通过 v-bind Vue.component('storage', data: return message= 从另一个组件发送它,//说它通过 axios 调用获取数据 ,.... ) 当你想显示它时你想告诉同一个产品组件它s about to get some props <template>
我会将动物名称/id 作为路由参数传递给显示页面,并让该组件负责获取和显示相关的动物数据。这样就避免了用户可以直接通过 URL 访问显示页面并看到一个不完整的页面的情况。
在您希望在页面之间共享本地状态的情况下,正如其他人指出的那样,您可能希望使用Vuex。
编辑:
我正在按照 OP 的要求在我的答案中添加一些代码。
路线:
const routes = [
path: "/", component: SearchAnimals ,
path: "/viewanimal/:name", component: DisplayAnimal, name: "displayAnimal"
];
DisplayAnimal.vue:
<template>
<div>
<p>Animal name: animal.name</p>
<p>Fur color: animal.furColor</p>
<p>Population: animal.population</p>
<p>Is extinct: animal.isExtinct</p>
<p>Is domesticated: animal.isDomesticated</p>
</div>
</template>
<script>
import axios from "axios";
export default
name: "DisplayAnimal",
data: () => (
animal:
),
methods:
fetchAnimal(name)
axios
.get(`http://localhost:8088/animalsapi?animal=$name`)
.then(response =>
this.animal = response.data;
);
,
created()
this.fetchAnimal(this.$route.params.name);
;
</script>
SearchAnimals.vue:
<template>
<form v-on:submit.prevent="onSubmit">
<textarea
v-model="animal"
name="animal"
type="animal"
id="animal"
placeholder="Enter your animal here"
></textarea>
<button type="submit">Get animal</button>
</form>
</template>
<script>
export default
name: "SearchAnimal",
data: () => (
animal: ""
),
methods:
onSubmit()
this.$router.push(
name: "displayAnimal",
params: name: this.animal
);
;
</script>
显然这是一个简单的示例,因此不包含任何错误处理等,但它应该可以让您启动并运行。
【讨论】:
我真的不想这样限制自己 - 也许以后我想通过用户提供的毛皮颜色来获得动物:fur color -> form -> server -> returns animal -> DisplayAnimal.vue -> displaying the animal
而您的解决方案需要fur color -> form -> server -> returns animal with that fur color -> pass animal name to DisplayAnimal.vue -> server -> returns animal with that name -> displaying the animal
我可以看到我最好的选择是将数据作为 HTTP 参数传递给DisplayAnimal.vue
。我在考虑可能将数据作为 POST 参数传递:animal name/fur/whatever -> form -> server -> returns animal -> GetAnimal.vue creates a POST request with JSON animal as a request parameter -> redirects to the DisplayAnimal.vue with the POST JSON animal parameter being passed to the GetAnimal.vue
。有可能吗?
我想这取决于你想要达到的目标。鉴于您刚才所说,为什么要将动物展示视为单独的路线?查询 API 并在同一路径中显示返回的动物数据似乎更有意义。
但为此我必须摆脱我已经拥有的元素 - 接受用户输入的表单。如果我以后想在其他地方展示动物怎么办?我必须重复显示代码?您将如何在同一页面中执行此操作?以某种方式删除表单元素并将其替换为显示动物数据的 div?如果该页面上有很多元素要删除怎么办?
嗯,这一切都取决于你的页面布局。你可以换掉组件,用结果替换表单,或者你选择在表单旁边显示数据(可能更好的 UI)。如果显示代码是一个接收动物作为道具的组件,那么在其他地方重用它很简单。【参考方案4】:
使用Vuex,你可以轻松解决这个问题
netlify 上的工作示例 https://m-animalfarm.netlify.app/
github上的代码 https://github.com/manojkmishra/animalfarm
GetAnimal.vue(我已禁用 axios 调用以进行测试和硬编码信息)
<template>
<form v-on:submit.prevent="getAnimal()">
<textarea v-model = "animal" name = "animal" type="animal" id = "animal"
placeholder="Enter your animal here">
</textarea>
<button class = "custom-button dark-button"
type="submit">Get animal</button>
</form>
</template>
<script>
import axios from 'axios';
export default
name: 'App',
data: function() return info: '', animal: '' ,
methods:
getAnimal: function()
// axios
// .get('http://localhost:8088/animalsapi?animal=' + this.animal)
// .then(response => (this.info = response.data),
this.info="fur-color": "yellow","population": 51000,"isExtinct":
false,"isDomesticated": true ,
this.$store.dispatch('storeAnimals', this.info)
//);
</script>
DisplayAnimal.vue
<template>
<div>
<p>Animal name: stateAnimal.animal</p>
<p>Fur color: stateAnimal.furColor</p>
<p>Population: stateAnimal.population</p>
<p>Is extinct: stateAnimal.isExtinct</p>
<p>Is domesticated: stateAnimal.isDomesticated</p>
</div>
</template>
<script>
import mapState, mapGetters from 'vuex';
export default
computed: ...mapState( stateAnimal:state => state.modulename.stateAnimal ),
,
</script>
modulename.js(存储模块)
export default
state: stateAnimal:null, ,
getters: ,
mutations:
['STORE_ANIMALS'] (state, payload)
state.stateAnimal = payload;
console.log('state=',state)
,
,
actions:
storeAnimals: (commit, data) =>
console.log('storeanim-data-',data);
commit( 'STORE_ANIMALS', data );
,
Index.js(用于 vuex 存储),如果页面刷新,您可以禁用持久状态作为保存状态
import Vue from 'vue'
import Vuex from 'vuex'
import modulename from './modules/modulename'
import createPersistedState from "vuex-persistedstate";
Vue.use(Vuex)
export default new Vuex.Store(
plugins: [createPersistedState( storage: sessionStorage )],
state: ,
mutations: ,
actions: ,
modules: modulename
)
所有组件的状态都可用/共享
【讨论】:
感谢您的回答。我应该运行modulename.js
和index.js
吗?或者我应该如何处理这些文件?另外,$store.storeAnimals
变量是全局变量吗?正如您所说,所有组件都可以访问它。如果我在两个不同的页面上有两个表单,同一用户同时用不同的动物填写这些表单怎么办 - 这些表单应该指向将显示两种动物的 DisplayAnimal.vue
页面 - 但如果动物存储在全局变量中,它会被覆盖,所以本质上会展示相同的动物——最后写入商店的那个?
Vuex store 包含在路由器等 vue 项目的 main.js 中。我已删除模块并将所有 vuex 代码包含在 github repo 上 store 文件夹的 index.js 中。是的 vuex 状态变量是全局的。你是对的——如果你将两种形式的东西存储在同一个状态变量中,它将更新为最新值。但是您可以将来自 diff 表单的值存储在 diff 状态变量中,以防您希望它们分开并且它们都将在全局范围内可用。
但是DisplayAnimal.vue
不是只查看$store
中的单个变量来显示吗?如果我要同时打开未知数量的表格怎么办?我必须为每个变量创建一个单独的变量吗?我真的很抱歉这么说,但这对我来说似乎不是一个可行的解决方案。
我来自 Java,这非常简单地完成了 - 没有任何全局变量 - .jsp
或 .html
页面查看了 HttpRequest
对象并从中获取attribute
:attribute
是与该特定请求相关联的一条数据。所以服务器只会将 JSON 附加到请求中:request.setAttribute("animal", animalJsonString);
,页面将<p>request.get("animal")</p>
。
那是伪代码,但你明白了要点。在我看来,vue
似乎没有这样的属性?但我认为vuex
的工作方式类似——但事实并非如此——我心中的全局状态是针对不同的事物、应用程序特定的事物:比如整个应用程序只有一个动物等等——不是特定于请求的数据片段 - 所以看起来我使用 vue 的唯一选择是将动物 JSON 数据作为 GET
或 POST
参数传递。看到GET
参数的长度是有限的,那就是POST
参数。以上是关于Vue:在另一个页面上显示来自表单提交的响应的主要内容,如果未能解决你的问题,请参考以下文章