在vue3中创建多重布局的方法
在本文中,会通过demo
演示来讲解几个用于创建多重布局的方式。
demo
需求:创建一个带有主页、营销页面和应用程序页面的 Web
应用程序
1. 导入Layouts作为常规组件来创建布局系
这是创建布局最简单的方法,但灵活性较差。
创建一个layouts
文件夹,在其中创建 3 个包含slot
的布局组件。
然后,只需在每个页面组件中导入所需的布局,如下所示:
该方法有两个主要问题:
-
需要导入每个页面的布局
当然,可以使这些组件全局化,但仍然需要每次手动包装内容。 -
每次路由改变时,布局都会被卸载并销毁,即使下一个路由使用相同的布局
这对性能影响很小,但真正的问题是,即使它们使用相同的布局,我们也无法保留从一条路由到另一条路由的状态。
2.使用Vue Router、路由的meta属性和动态组件创建布局
为了避免在每个页面中导入布局,我们可以在路由器中导入一次,并为每个路由提供关联的布局。meta 元属性介绍
如此处所示,我们将每个布局组件对象直接与每个路由的元属性相关联。我们只导入一次所有布局。
为了避免布局被卸载和破坏,我们会将布局放在页面上方而不是页面内。
为了将布局放在页面上方,我们在 App.vue
组件中创建了一个动态组件
在模板中,我们可以通过$route
和path
来访问当前路由。我们可以访问它的元属性,这意味着我们可以访问之前设置的布局组件对象。
如果路由在元对象上没有布局属性,我们会回退到字符串使用 div
标签。
只导入一次布局,我们不需要导入甚至包装每个页面中的布局,现在,我们不会有性能问题,并且我们可以在从具有相同布局的 2 个路由导航时保持状态。
所以主页组件现在看起来像这样:
不再需要通过slot
插入任何东西;所有内容都在 App.vue
中围绕 <router-view>
进行处理,<router-view>
代表路由更改时的每个页面。
此方法适用于大多数用例,但有 1 个问题:
仅当path
改变时布局才会改变。
如果需要动态改变布局而不改变path
,这个方法就行不通了。
虽然只有少数情况下我们希望动态更改布局,但这种情况可能会存在,比如:
- 可能是在一段时间后显示锁定的页面
- 可能是显示离线页面
- 可能是显示错误页面
这些示例可以通过全屏弹窗来实现,但是弹窗很容易通过控制台从 DOM
中删除。
3.使用ShallowRef、Provide、Inject和Vue Router的afterEach钩子创建布局
为了能够从任何地方更改布局,而不仅仅是在path
更改时,我们需要在整个应用程序中共享布局的状态。
我们可以使用Vuex
或Pina
来实现这一点,但为了能简单的展示,本文使用 Vue
的原生响应式系统和组合 API
。
步骤如下:
-
在
App.vue
中,我们将创建一个布局常量,其中包含一个shallowRef
来保存当前布局组件 -
在一个单独的文件中,我们将创建一个带有键/值对的对象,其中包含每个布局的名称及其组件。
-
在
App.vue
或其他地方,我们将使用路由的afterEach
钩子监听每个路由变化,以动态更改当前布局 -
在
App.vue
中,我们将向其后代提供 布局常量,以便App.vue
树中的任何组件都可以注入 布局常量来更改其值。 -
在路由中,我们将元属性上的每个布局属性更改为仅包含要选择的布局名称的字符串。
将路由中的元更改为仅字符串,因为它们将映射到第2步中的对象:
现在让我们将所有代码整理一下:
为什么我们使用shallowRef
而不是ref
?
ref
将使基值和所有嵌套值变为响应式,但 shallowRef
只会使基值变为响应式。
由于我们存储的是一个组件,它是一个具有大量嵌套值的复杂对象,因此使用 ref
会导致性能问题。
其实也没有必要纠结使用是否要使用ref
,因为我们只需要知道整个组件何时更改,而不是嵌套值何时更改。
下面是一个可以通过单击更改其布局的主页示例:
如上面的代码所示,我们现在可以注入和访问布局的状态并将其更改为我们想要的任何组件。由于是响应式的,它将动态更改 App.vue
中的组件。
对于大多数场景来说,可以使用 Vuex
或 Pinia
执行相同的操作来实现共享状态。