Vue 组件设计思考
我们知道, Vue 是基于 MVVM 设计的一个前端框架, 是数据驱动页面显示的架构. 同时, 它是 Html 的模板引擎, 是 Vue 模板通过翻译器翻译成 Hmtl 语言. 这个 Vue 模板, 也就是组件, 在 Vue 中, 一切皆是组件.
一、路由模块化
在我们分析某一个页面组件结构之前, 我们必须要从 main.js 入口 的 路由 开始. 原因是:
页面的跳转通常都是通过路由 页面的结构少不了
<router-view />
这里除非只用 Vue 做移动 APP, 不用路由做导航.
main.js
简化了不必要的东西
import Vue from 'vue';
import App from './App.vue';
import router from './router';
new Vue({
router,
render: h => h(App)
}).$mount('#app');
router.js
这里简化了, 可以看到里面路由分模块了, 里面引入 user 模块, user 作为 Home 的子路由.
import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router);
const App = () => import('@/App');
const Home = () => import('@/modules/Home');
// 导入模块
import user from './modules/user';
/**
* 主页路由表,主页下面子路由放在这
*/
const homeRouter = [
{
path: '/',
component: App,
redirect: '/home'
},
{
path: '/home',
component: Home,
name: 'Home',
meta: {
title: 'common.breadCrumb.Home'
},
children: [ // 主页子路由
...user // 用户中心
]
}
];
export default router;
user.js
这里是用户模块, 里面可以放登录,注删,用户相关的页面导航
在 User 下面, 还有一个子导航 Login. 作跳转时, 只要加入<router-view /> 就可以做跳转.
const User = () => import('@/modules/user');
const Login = () => import('@/modules/login');
const Doing = () => import('@/modules/user/Doing');
export default [
{
path: '/user',
name: '用户中心',
component: User,
meta: {
title: 'common.breadCrumb.UserSet'
},
children: [
{
path: '/user/login',
name: 'UserLogin',
component: Login,
meta: {
title: 'common.breadCrumb.Login'
}
}
]
}
];
为什么路由要这样设计, 先看看 Home 页面组成, 我们拿百度页面来分析
图中 页脚组件, 如果是每一个页面都要显示. 那么我们是不是可以封装成
<Footer />组件放在最下面. 那么每一页都会出现.
<template>
<div id="app">
<div class="app-main">
<router-view />
</div>
<ATUFooter />
</div>
</template>
<script>
const Footer = () => import('modules/common/Footer');
export default {
name: 'App',
components: { Footer },
};
</script>
在比较, 我们跳传到用户模块里面, 如果有二个以上的页面有相同的组件, 是不是可以直接放到页面里面去. 通过子导航去页面 <router-view /> 跳转.
当然, 如果我们用不上导航, 也可以直接在页面作组件切换的刷新, 只是这样. 当页面多到一定数量时, 就不好管理.
二、页面的组件化
1、什么时候抽离成独立组件
我们拿百度首页来分析, 这里面有 5 个内容体, 分别是是页头的导航, 页脚信息等, 还要主要内容搜素, 新闻, 热搜.
这是一个简单的页面结构. 如果我们不做组件拆分, 只有一个人独立开发, 那么其实可以全部代码都写在 template 里面
一个功能一个功能慢慢的去实现.
<template>
<div id="home">
<div class="nav">
</div>
<div class="search">
</div>
<div class="news">
</div>
<div class="hot">
</div>
</div>
</template>
但是我们通常都是多人合作开发, 在这个页面里面多少人去写入代码这样真的好吗?
所以, 我们对这个页面作 4 个组件的拆分, 然后通过 Home 页合并到一起. 开发人员商量好共同的交互与数据, 然后独立的开发各自的组件.
<template>
<div id="home">
<Nav class="nav" />
<Search class="search" />
<News class="news" />
<Hot class="hot" />
</div>
</template>
组件的拆分一定要按实际情况出发, 不要为组件而组件, 把问题搞复杂化了.
比如一个下载按钮
- 如果这个下载只是简单的得到 Url 下载地址下载.那么就没有必要去封装成组件.
- 但是如果这个下载, 里面要做大量的业务逻辑处理, 去别的模块取值做计算等, 里面大量复杂代码会影响主组件的简洁, 那么抽取出来做独立处理更好一点.
2、组件之间的数据交互
组件之间的数据的交互方式官网上说的很清楚了, 我就简单说一点, 通常是以下三种情况:
a. 父组件与子组件交互
父组件传到子组件可以通过 props, 反过来, 子组件传到父组件用 this.$emit() 传出去.
b. 兄弟组件交互
可以通过父组件传交互, 但是实际用起来,有时会传不到. 这时也可以通过 store 做中传.
c. 祖组件与孙组件交互
祖组件到孙组件, 一层层传下去. 反过来, 官网也有方法, 但是用起来好像有问题, 建议还是通过 store 处理.
3、组件的网络请求与数据业务逻辑应该放在那里.
按实现情况出发吧
- 如果这个组件是多个模块共用, 数据来源不一样, 那么最好是数据是从外面,也就是父组件转进来. 这样能最大限度保持它的通用性.
- 如果这个组件是多个模块共用, 但是数据来源是一样, 那么最好的是把数据请求, 业务逻辑等一起封装在里面. 这样好处是保护父组件的简洁性.
- 如果这个组件是独立的, 那么最好是把数据请求, 业务逻辑等一起封装在里面.
3. 最后
我个人建议是, 组件数据请求、业务逻辑等代码能写在里面最好写在里面, 独立封装, 这样能够分化父组件的代码. 不用全部代码写在一起. 当然, 如果这个组件是公用组件, 那么又是另外一回事. 数据必须是外面传进来.
如果封装在里面了, 数据传出去, 就按上面数据交互来做, 但是通常, 都是网络清求数据, 在网络发送出去. 只有少数据情况下才会用到里面页面传递.
大部分的开发都是多人开发, 所以做好模块化或者说组件化的开发是很重要的.
以上只是个人见解, 如果有说的不对的地方, 欢迎指正讨论, 谢谢.