前言
目前流行的前端UI元件庫都支援移動裝置優先的響應式佈局
特性。但基於Mobile和PC兩個場景的不同使用者體驗,也往往會實現Mobile和PC兩個版本。
PC場景下的Web工程,如大量的後臺前端管理模版
,雖然支援Mobile自適應,但其使用者體驗差強人意。
Cabloy採用不同的思路,仍然基於移動優先
,同時通過特殊的佈局優化,使得移動頁面可以完整的用於PC場景,既保證了使用者體驗,又提升了開發效率,大大簡化了開發工作量。
演示
- PC:demo.cabloy.org
- Mobile:
上圖
Mobile佈局
PC佈局
進一步分析
Cabloy的PC佈局
將頁面切分為若干個Mobile+Pad
的組合,帶來了與眾不同的使用者體驗。
從此開發類似於微信公眾號
或H5混合開發
的專案,再也不用建立兩套獨立的工程。
內部機制
Cabloy前端基於Framework7
,並一直跟進其最近的開發進度,從1.0到2.0,再到3.0。Cabloy充分利用了Framework7的優良特性,充分發揮其最大價值。
Cabloy的作者zhennann
在Framework7
的貢獻圖如下:
Framework7將頁面分為若干個View,每個View對應一個Router,管理若干個Page,從而非常方便的實現Page之間的堆疊。
Cabloy的PC佈局
,將頁面分為若干個Tab,每個Tab再包含若干個View。通過對Router的patch,實現Tab之間與View之間的URL跳轉。
程式碼實現
根結點元件
Cabloy通過不同的模組
封裝不同佈局的實現邏輯,然後在根結點元件
中針對頁面的尺寸的變化渲染不同的佈局。
需要特別說明的是,Cabloy中的模組
是一個相對獨立的實體,可以根據需要非同步載入
,提升頁面載入效能。
egg-born-front/src/base/mixin/config.js
:
config.js配置佈局資訊,可通過修改配置實現自己的佈局管理邏輯
// config
const config = {
modules: {},
layout: {
breakpoint: 800,
items: {
mobile: {
module: 'a-layoutmobile',
component: 'layout',
},
pc: {
module: 'a-layoutpc',
component: 'layout',
},
},
},
};
複製程式碼
egg-born-front/src/inject/pages/app.vue
:
app.vue是根結點元件,動態非同步載入所需的佈局元件
<script>
import Vue from 'vue';
export default {
render(c) {
const children = [];
// statusbar
children.push(c('f7-statusbar', { ref: 'statusbar' }));
// layout
if (this.layout) {
children.push(c(this.layout, {
ref: 'layout',
}));
}
const app = c('f7-app', { props: { params: this.$root.$options.framework7 } }, children);
return c('div', [ app ]);
},
data() {
return {
layout: null,
};
},
methods: {
ready() {
if (this.$f7.device.ie) {
this.$f7.dialog.alert('Supports All Modern Browsers Except IE');
return;
}
// check query
const documentUrl = location.href.split(location.origin)[1];
if (documentUrl && documentUrl.indexOf('/?') === 0) {
history.replaceState(null, '', location.origin);
}
// hash init
const hashInit = this.$meta.util.parseHash(location.href);
if (hashInit && hashInit !== '/') this.$store.commit('auth/setHashInit', hashInit);
// on resize
this.$f7.on('resize', this.onResize);
// auth echo first
this._authEcho(() => {
// resize
this.resize();
});
},
getLayout() {
return this.$refs.layout;
},
resize() {
// layout
const breakpoint = this.$meta.config.layout.breakpoint;
let layout = window.document.documentElement.clientWidth > breakpoint ? 'pc' : 'mobile';
if (!this.$meta.config.layout.items[layout]) {
layout = layout === 'pc' ? 'mobile' : 'pc';
}
// check if switch
if (this.layout === layout) {
const component = this.getLayout();
if (component) component.onResize();
} else {
// load module layout
this.$meta.module.use(this.$meta.config.layout.items[layout].module, module => {
this.$options.components[layout] = module.options.components[this.$meta.config.layout.items[layout].component];
// clear router history
this.$meta.util.clearRouterHistory();
// ready
this.layout = layout;
});
}
},
reload(ops) {
ops = ops || { echo: false };
if (ops.echo) {
this._authEcho(() => {
this._reloadLayout();
});
} else {
this._reloadLayout();
}
},
onResize: Vue.prototype.$meta.util.debounce(function() {
this.resize();
}, 300),
login(url) {
const hashInit = this.$store.state.auth.hashInit;
this.$store.commit('auth/setHashInit', null);
url = `${url}?returnTo=${encodeURIComponent(this.$meta.util.combineHash(hashInit))}`;
location.assign(url);
},
_authEcho(cb) {
// get auth first
this.$api.post('/a/base/auth/echo').then(user => {
this.$store.commit('auth/login', {
loggedIn: user.agent.anonymous === 0,
user,
});
return cb && cb();
}).catch(() => {
return cb && cb();
});
},
_reloadLayout() {
const layout = this.layout;
this.layout = null;
this.$nextTick(() => {
// clear router history
this.$meta.util.clearRouterHistory();
// restore layout
this.layout = layout;
});
},
},
beforeDestroy() {
this.$f7.off('resize', this.onResize);
},
mounted() {
this.$f7ready(() => {
this.ready();
});
},
};
</script>
複製程式碼
Mobile佈局元件
Mobile佈局元件原始碼參見:github.com/zhennann/eg…
a-layoutmobile/front/src/config/config.js
:
config.js可以靈活配置佈局的顯示元素
export default {
layout: {
login: '/a/login/login',
loginOnStart: true,
toolbar: {
tabbar: true, labels: true, bottomMd: true,
},
tabs: [
{ name: 'Home', tabLinkActive: true, iconMaterial: 'home', url: '/a/base/menu/list' },
{ name: 'Atom', tabLinkActive: false, iconMaterial: 'group_work', url: '/a/base/atom/list' },
{ name: 'Mine', tabLinkActive: false, iconMaterial: 'person', url: '/a/user/user/mine' },
],
},
};
複製程式碼
PC佈局元件
Mobile佈局元件原始碼參見:github.com/zhennann/eg…
a-layoutpc/front/src/config/config.js
:
config.js可以靈活配置佈局的顯示元素
export default {
layout: {
login: '/a/login/login',
loginOnStart: true,
header: {
buttons: [
{ name: 'Home', iconMaterial: 'dashboard', url: '/a/base/menu/list', target: '_dashboard' },
{ name: 'Atom', iconMaterial: 'group_work', url: '/a/base/atom/list' },
],
mine:
{ name: 'Mine', iconMaterial: 'person', url: '/a/user/user/mine' },
},
size: {
small: 320,
top: 60,
spacing: 10,
},
},
};
複製程式碼
結語
Cabloy是採用Javascript進行全棧開發的最佳實踐。 Cabloy不重複造輪子,而是採用業界最新的開源技術,進行全棧開發的最佳組合。 歡迎大家拍磚、踩踏。 地址:github.com/zhennann/ca…