Cabloy全栈JS框架微创新之一:不一样的“移动优先 PC适配”

前言

目前流行的前端UI组件库都支持移动设备优先的响应式布局特性。但基于Mobile和PC两个场景的不同用户体验,也往往会实现Mobile和PC两个版本。
PC场景下的Web工程,如大量的后台前端管理模版,虽然支持Mobile自适应,但其用户体验差强人意。
Cabloy采用不同的思路,仍然基于移动优先,同时通过特殊的布局优化,使得移动页面可以完整的用于PC场景,既保证了用户体验,又提升了开发效率,大大简化了开发工作量。

演示

cabloy-demo-qrcode.png

上图

Mobile布局

layout-mobile.png

PC布局

layout-pc.png

进一步分析

Cabloy的PC布局将页面切分为若干个Mobile+Pad的组合,带来了与众不同的用户体验。
从此开发类似于微信公众号H5混合开发的项目,再也不用建立两套独立的工程。

内部机制

Cabloy前端基于Framework7,并一直跟进其最近的开发进度,从1.0到2.0,再到3.0。Cabloy充分利用了Framework7的优良特性,充分发挥其最大价值。
Cabloy的作者zhennannFramework7的贡献图如下:

f7-zhennann.jpg

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布局组件源码参见:https://github.com/zhennann/egg-born-module-a-layoutmobile/blob/master/front/src/components/layout.vue

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布局组件源码参见:https://github.com/zhennann/egg-born-module-a-layoutpc/blob/master/front/src/components/layout.vue

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不重复造轮子,而是采用业界最新的开源技术,进行全栈开发的最佳组合。
欢迎大家拍砖、踩踏。
地址:https://github.com/zhennann/cabloy

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是使用 Bootstrap 前端框架制作一个移动端和 PC 端都适配的选项卡页面的基本步骤: 1. 引入 Bootstrap 的样式和脚本文件 在 HTML 文件中引入 Bootstrap 的 CSS 样式文件和 JavaScript 脚本文件。 ```html <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.5.3/css/bootstrap.min.css"> <script src="https://cdn.staticfile.org/jquery/3.5.1/jquery.min.js"></script> <script src="https://cdn.staticfile.org/popper.js/1.16.0/umd/popper.min.js"></script> <script src="https://cdn.staticfile.org/twitter-bootstrap/4.5.3/js/bootstrap.min.js"></script> ``` 2. 创建 HTML 结构 在页面中创建一个 div 容器,用于显示选项卡内容。然后在容器中使用 Bootstrap 的 nav 组件创建一个选项卡导航栏,每个选项卡对应一个内容区域。 ```html <div class="container"> <ul class="nav nav-tabs" id="myTab" role="tablist"> <li class="nav-item"> <a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a> </li> <li class="nav-item"> <a class="nav-link" id="profile-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Profile</a> </li> <li class="nav-item"> <a class="nav-link" id="contact-tab" data-toggle="tab" href="#contact" role="tab" aria-controls="contact" aria-selected="false">Contact</a> </li> </ul> <div class="tab-content" id="myTabContent"> <div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab"> <h1>Home</h1> <p>This is the home page.</p> </div> <div class="tab-pane fade" id="profile" role="tabpanel" aria-labelledby="profile-tab"> <h1>Profile</h1> <p>This is the profile page.</p> </div> <div class="tab-pane fade" id="contact" role="tabpanel" aria-labelledby="contact-tab"> <h1>Contact</h1> <p>This is the contact page.</p> </div> </div> </div> ``` 3. 添加响应式布局 为了适应移动端设备,我们需要在容器的 class 属性中加入 `mx-auto` 和 `mt-5` 两个类,分别控制内容区域在中央显示和与导航栏之间的间距。同时,我们还需要为选项卡导航栏和内容区域添加响应式布局,使它们在移动端和 PC 端都能够适配。 ```html <div class="container mx-auto mt-5"> <ul class="nav nav-tabs nav-justified" id="myTab" role="tablist"> ... </ul> <div class="tab-content" id="myTabContent"> ... </div> </div> ``` 4. 添加样式和效果 为了让页面更加美观大气,我们可以添加一些样式和效果。比如,我们可以给选项卡导航栏添加背景色和圆角边框,给选项卡添加悬停效果等。 ```html <style> .nav-tabs { background-color: #f8f9fa; border-radius: 5px; } .nav-tabs .nav-link { border-radius: 5px 5px 0 0; } .nav-tabs .nav-link:hover { background-color: #e9ecef; } .tab-pane { padding: 20px; background-color: #f8f9fa; border-radius: 5px; margin-top: 10px; } </style> ``` 以上就是使用 Bootstrap 前端框架制作一个移动端和 PC 端都适配的选项卡页面的基本步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值