Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chameleon 之强大的多态协议 #3

Closed
Bowen7 opened this issue Jan 31, 2019 · 0 comments
Closed

chameleon 之强大的多态协议 #3

Bowen7 opened this issue Jan 31, 2019 · 0 comments

Comments

@Bowen7
Copy link
Owner

Bowen7 commented Jan 31, 2019

访问 https://bowencodes.com 以获得最佳体验

Chameleon(变色龙)是滴滴最近开源的一个跨端解决方案,趁着寒假,我花了些时间学习并使用了Chameleon,本文主要是探究它强大的多态协议

优势

当下的跨端框架层出不穷,但基本都是在框架提供的跨端能力基础上进行开发,而业务逻辑不可能跟着框架走,有时候开发者需要突破框架的限制;同时,web、小程序、native存在端上的差异,它们的需求在某些业务上可能不同,需要我们人为地做环境判断,逻辑一旦复杂,跨端数量一旦很多,代码就会变得可读性低,难以维护,这并不是我们跨端的本意

变色龙基于统一多态协议,开发者可以自由扩展api和组件,使用各端众多的开源库,不再拘囿于框架。同时,将特有代码进行隔离,避免各端互相影响,并保持逻辑连续性(优雅的跨端实现)

多态协议

多态协议提供了跨端时各端底层组件与接口统一的解决方案,用户可以自己开发跨端api和组件,也可以根据需求轻松变换各端的表现,变色龙会在编译时拆分各端代码,保证各端代码的纯正性,这也是我使用变色龙感觉到最舒服的一个地方

多态组件

我们可以执行cml init component,选择多态组件,输入文件名,即可快速生成多态组件模版,结构如下:

./src/components
└── xxx
    ├── xxx.interface
    ├── xxx.web.cml
    ├── xxx.weex.cml
    └── xxx.wx.cml

变色龙会提供一个最简单的多态组件模版,你可以自由填充。xxx.interface描述组件的属性和方法,剩下的文件是各端的具体实现,在多态组件中,我们可以在cml文件里任意使用对应端的功能、标签,还可以引入当前端的成熟开源库,甚至还能直接引入web端、小程序端的组件,并且变色龙会帮你检查和隔离代码,不会出现A端的代码一不小心去了B端的情况

假设现在有这样一个需求,我们需要跨端展示markdown格式的文章,首先,我们需要把markdown格式的文章转换为html:

const prism = require("prismjs");
const md = require("markdown-it")({
  highlight: function(str, lang) {
    try {
      return (
        prism.highlight(str, prism.languages[lang], lang)
      );
    } catch (__) {
      console.log(__);
    }
    return "";
  }
});

很简单,在引入两个包和执行上面的代码之后,我们传入mdText执行md.render(mdText)就可以获得带代码格式的html字符串,那我们如何跨端渲染html呢?h5端似乎可以直接用v-html,但小程序端不支持这么多的标签,只能把它放在rich-text里,weex端的rich-text功能太弱,只能放spanaimg三种标签,不能承载markdown转html后的标签数量,这三端需要同时兼容,各种代码交织在一起,想想就头疼,别提更多端数了

那我们如何去实现这个功能呢,我们先查阅文档,发现变色龙还没有可以直接用的解决方案,没关系,我们可以自己写一个多态组件:

首先,创建多态组件,我命名为rich-text,它接受一个属性html,为需要渲染的html字符串

rich-text.interface文件如下:

<script cml-type="interface">
interface RichTextInterface {
  html: String
}
</script>

先看微信端,微信提供了rich-text组件,可以通过给标签加上前缀origin-拿到该端的原生标签, 我们用origin-rich-textrich-text.wx.cml中拿到微信小程序原生的rich-text(以下代码可能有省略):

<template>
  <origin-rich-text nodes="{{_html}}">
  </origin-rich-text>
</template>

<script>

class RichText implements RichTextInterface {
  props = {
    html: {
      type: String,
      default: ''
    }
  }

  computed = {
    _html(){
      return this.html
      .replace(/\n/g,'<br/>')
      .replace(/<pre>|<\/pre>/g,'');
    }
  }
}
export default new RichText();
</script>

<style >
  @import "./prism.css";
</style>

需要注意,微信的rich-text不支持pre标签,所以我们需要过滤pre标签并人为加上换行(这里只是一个示例demo,还有可能有其他不支持的标签我没注意)

web端可以直接使用v-html,我这里为了演示引入web端组件,所以单独创建了一个rich-text-vue.vue文件,如下

<template>
  <div v-html="html">
  </div>
</template>
<script>
class Index {
  props = {
    html:{
      type: String,
      default: ''
    }
  }
};
export default new Index();
</script>
<style>
 @import "./prism.css";
</style>

这是一个纯正的vue组件,后缀也是纯正的.vue,我们可以在rich-text.web.cml中直接引用它,如下:

<template>
  <rich-text-vue html="{{html}}">
  </rich-text-vue>
</template>

<script>

class RichText implements RichTextInterface {
  props = {
    html: {
      type: String,
      default: ''
    }
  }
}

export default new RichText();
</script>

<style >

</style>

<script cml-type="json">
{
  "base": {
    "usingComponents": {
      "rich-text-vue": "./rich-text-vue"
    }
  }
}
</script>

当然,我们还可以在其他端引入小程序组件等等,导入与导出,这里就不多示范了

最后是weex端,weex的rich-text接受的标签是在太少,我最后决定使用weex的web组件实现,创建rich-text-weex.vue,写入代码:

<template>
  <div class="wrapper">
    <web
    style="width: 730px; height: 500px"
    src="http://192.168.0.102:8000/cml/h5/index">
    </web>
  </div>
</template>

<style scoped>
  .wrapper {
		flex-direction: column;
		padding: 10px;
	}
</style>

<script>
  module.exports = {
    data: {
    }
  }
</script>

其中http://192.168.0.102:8000/cml/h5/index是我本机跑着的地址

至此,h5,小程序,weex的工作都已完成,只需要引入该组件,并在页面插入一行代码:

<rich-text html="{{html}}"></rich-text>

传入html字符串,我们就能看到效果了

下图是我最后的效果图,分别是h5,小程序,weex端

这只是一个简单的例子,官网还有关于如何跨端使用echarts的例子

多态接口

多态接口与多态组件类似,不过是把组件的形式换成了接口,同样,输入cml init component,选择多态接口,输入文件名xxx,会生成以下结构文件:

├── components
    └──xxx
      └── xxx.interface

为了方便说明,我写了一个跨端的storage接口,当然,变色龙有更强大的内置storage方法

新建多态接口,命名为storage,向storage.interface文件写入以下代码:

<script cml-type="interface">
interface StorageInterface {
  get(key: string): Promise;
  set(key: string, value: string): Promise;
}

</script>

<script cml-type="web">

class Method implements StorageInterface {
  get(key) {
    return Promise.resolve(localStorage.getItem(key));
  }
  set(key, value){
    localStorage.setItem(key,value);
    return Promise.resolve();
  }
}

export default new Method();
</script>

<script cml-type="weex">
const storage = weex.requireModule('storage');
class Method implements StorageInterface {
  get(key) {
    return new Promise((resolve)=>{
      storage.getItem(key, event => resolve(event.data));
    })
  }
  set(key, value){
    return new Promise((resolve)=>{
      storage.setItem(key, value, resolve);
    })
  }
}

export default new Method();
</script>

<script cml-type="wx">

class Method implements StorageInterface {
  get(key) {
    return Promise.resolve(wx.getStorageSync(key));
  }
  set(key, value){
    wx.setStorageSync(key, value);
    return Promise.resolve();
  }
}

export default new Method();
</script>

我简单地实现了storagegetset方法,因为weex端的storage是异步的,为了统一,所以我规定getset方法的返回值为Promise,后面的具体实现就很简单了,查查文档就能写出来了

然后,只用import storage from "../../components/storage/storage.interface";引入接口,就可以调用storage.get()storage.set()来达到跨端的storage操作了

多态样式

多态样式则比较简单,cml文件中的style如下即可实现样式多态:

<style>
.common {
}
@media cml-type (web) {
  .class1 {
    color: red;
  }
}
@media cml-type (weex) {
  .class1 {
    color: green;
  }
}
@media cml-type (wx,alipay,baidu) {
  .class1 {
    color: blue;
  }
}
</style>

总结

Chameleon的统一多态协议让开发者有了更多的施展空间,我们可以在框架的基础上自由开发api和组件,在遇到个别不同端差异化实现的情况也能优雅保持代码逻辑的连续性,并有效隔绝各端代码

整个项目,可能跨端框架的功能能涵盖95%的工作,但剩下的5%才是关键,基于多态协议,我们可以优雅轻松地完成这5%的工作

当然,Chameleon还有其他强大之处,比如强大的基础库、跨多端语法检查功能、导入导出原生组件、Chameleon iOS SDK、Chameleon Android SDK等等

chameleon使用体验

官网

github

@Bowen7 Bowen7 changed the title Chameleon之强大的多态协议 chameleon之强大的多态协议 Jan 31, 2019
@Bowen7 Bowen7 changed the title chameleon之强大的多态协议 3. chameleon 之强大的多态协议 Aug 4, 2020
@github-actions github-actions bot changed the title 3. chameleon 之强大的多态协议 chameleon 之强大的多态协议 Aug 6, 2020
@Bowen7 Bowen7 removed the chameleon label Dec 28, 2020
@Bowen7 Bowen7 closed this as completed Apr 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant