刷新时指示 vue-router 重新渲染正确的页面 [英] Instruct vue-router to re-render correct page when refresh
问题描述
我的应用程序是由 vuejs + rails 构建的,它具有以下路由器组件:
My application is built by vuejs + rails, it has these router components:
{
path: '/',
name: 'home',
component: Home,
children: [
{
path: '/',
name: 'welcome',
component: Welcome,
},
{
path: '/classes/:id',
name: 'class',
component: Class,
},
{
path: '/classes/:id/members',
name: 'member',
component: Member,
},
{
path: '/account',
name: 'account',
component: Account,
},
...
]
},
当我导航链接时,路由器链接部分工作正常,但是当我站在 /classes/1 path
并刷新 url 时,它导致未找到错误:
The router-link parts work fine when I navigate the link, but when I'm standing in /classes/1 path
and refresh the url, it result a not found error:
没有路由匹配[GET]/classes/1"
我明白刷新的时候,我向服务器发出了一个新的请求,所以我添加了这个Rails 路由器中的路由:
I understand that when I refresh, I make a new request to the server, so I added this routing in rails router:
get '/*path', to: 'home#index'
因此,它不会引发错误,而是使主页成功,但这不是我想要的.我希望它仍然保留或重新加载我所在的当前页面.如果我在 /classes/1
并点击刷新,它应该保持/刷新 /classes/1
页面.我怎样才能做到这一点?
So instead of raising an error, it render home page successful but that is not what I want.
I want it still keep or reload the current page where I 'm in.
If I'm in /classes/1
and hit refresh, it should keep/refresh /classes/1
page.
How can I achieve this?
推荐答案
这里是我在工作中所做的应用程序关键部分的修改版本.
Here are modified versions of key parts of an app I did at work.
# config/routes.rb
# frozen_string_literal: true
Rails.application.routes.draw do
root('application#index')
# I use a scope because in the real app I also have other routes such as
# browserconfig.xml and site.webmanifest which are both procedurally
# generated.
scope('/', format: false) do
# Catch all for HTML 5 history routing. This must be the last route.
get('*path', to: 'application#index')
end
# equivalent, if scope is unnecessary
# get('/*path', to: 'application#index', format: false)
end
# app/controllers/application_controller.rb
# frozen_string_literal: true
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def index
# Avoid having an empty view file.
render(inline: '', layout: 'application')
end
end
/ app/views/layouts/application.html.slim
doctype html
html
head
/ ...
body
main
/ Webpacker 4.3.0
= javascript_packs_with_chunks_tag('main', defer: true)
在我的 JS 代码中,我在 main
元素上挂载了一个 Vue 实例.所有客户端/Vue 路由都通过我的 Vue 路由器处理.我有一个JS目录树结构如下:
In my JS code, I mount a Vue instance on the main
element. All client-side/Vue routes are handled through my Vue router. I have a JS directory tree structure as follows:
project_root/
|-- src/
|-- api/ <- external REST API handling code
|-- channels/ <- Action Cable stuff
|-- components/ <- Vue SFC's and functional components
|-- images/ <- image files
|-- lib/ <- various local library code
|-- mixins/ <- Vue component mixins
|-- packs/ <- all files in here are picked up by Webpacker; these are the entry-points
|-- main.mjs <- imports pages/main.mjs (my app has multiple packs and pages, and there's "some" logic behind this structure)
|-- pages/
|-- main.mjs <- does the heavy lifting of building the Vue instance
|-- plugins/ <- Vue plugins
|-- scss/ <- SCSS files
|-- store/ <- Vuex stuff
|-- vendor/ <- third-party vendor stuff, like poly-fills
|-- main.mjs
// src/pages/main.mjs
import '@/scss/main.scss';
// this should be first to ensure `vendors` loads first
import build from '@/main';
import VuexRouterSync from 'vuex-router-sync';
import App from '@/components/app.vue';
import router from '@/lib/router';
import store from '@/store';
build(
App,
{
router,
store,
},
(Vue) => {
Vue.use(BootstrapVueUtils);
VuexRouterSync.sync(store, router);
},
);
// src/main.mjs
import '@/vendor';
import isFunction from 'lodash-es/isFunction';
import Vue from 'vue';
export default function build(appComponent, config = {}, preInit = null) {
// call Vue.use here for any plugins that are common to all packs/pages
// Vue.use(Vuelidate);
if (preInit == null && isFunction(config)) {
preInit = config;
config = {};
}
if (isFunction(preInit)) {
preInit(Vue);
}
function init() {
new Vue({
beforeCreate() {
Vue.$rootVm = this;
},
render(h) {
return h(appComponent);
},
...config,
}).$mount('main');
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
}
// src/lib/router.mjs
import Vue from 'vue';
import VueRouter from 'vue-router';
import Folder from '@/components/folders/show.vue';
import Folders from '@/components/folders'; // index.vue
import Home from '@/components/home.vue';
import LogIn from '@/components/log-in.vue';
import NotFound from '@/components/not-found.vue';
import Settings from '@/components/settings'; // index.vue
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
saveScrollPosition: true,
routes: [
{
path: '/',
redirect: '/folders',
component: Home,
children: [
{
name: 'folders',
path: 'folders',
component: Folders,
},
{
name: 'folder',
path: 'folders/:id',
component: Folder,
},
{
name: 'settings',
path: 'settings',
component: Settings,
},
],
},
{
name: 'log-in',
path: '/log-in',
component: LogIn,
},
// This isn't necessary, and I question it now. Has no effect on the functioning of the router.
{
name: 'not-found',
path: '*',
component: NotFound,
}
],
});
// There's some additional code after this to setup event handling on the
// `router`, specifically `router.beforeEach` to check the logged-in status
// and if not logged in redirect to the log-in route.
这是很多代码,但我想尝试涵盖从 Rails 路由器到 Vue 路由器的所有内容,还包括一些可能有帮助的额外内容.
This is a lot of code, but I wanted to try and cover everything from Rails router to Vue router, and also include some extra stuff that might help.
我确实注意到您在 'home'
Vue 路由的 children 数组中包含了前导 /
.这是不必要的,因为它是基于父级隐含的.
I did notice that you included the leading /
in the children array of your 'home'
Vue route. That's unnecessary as it's implied based on the parent.
来自 Vue 路由器文档:
请注意,以/开头的嵌套路径将被视为根路径.这允许您利用组件嵌套而不必使用嵌套 URL.
Note that nested paths that start with / will be treated as a root path. This allows you to leverage the component nesting without having to use a nested URL.
所以,虽然没有必要,但我认为这不是您问题的原因.
So, while unnecessary, I don't think it's the cause of your issue.
我唯一能想到的就是绝对确定 Rails 包罗万象的路线是最后一条路线.Rails 路由按照在 config/routes.rb
文件中指定路由的顺序从上到下匹配.
The only thing I can think of, is to make absolutely certain the Rails catch-all route is the very last route. Rails routing matches from top-bottom in order of how the routes are specified in the config/routes.rb
file.
这篇关于刷新时指示 vue-router 重新渲染正确的页面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!