Git Product home page Git Product logo

weex-eleme's Introduction

weex-eleme

常见问题(FAQ)

Demo软件页面

极客时间软件页面下载

Hot to run it?

git clone https://github.com/iChenLei/weex-eleme.git
cd weex-eleme

使用Android Studio打开项目,先使用gradle下载依赖jar包,然后run

Dev Road map

1.Implement Flash page
2.Implement tabbar and four important fragment page
3.complete user page and order page
4.implement shop page and shopping cart
5.add more animation
6.implement search feature
7.and more feature

MIT License @ichenlei 2017-present

weex-eleme's People

Contributors

ichenlei avatar poweryang avatar xkli avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

weex-eleme's Issues

从被问烂的新手问题[如何加载本地图片?]出发,浅谈weex的图片问题

新手问题 如何加载本地图片呀?

官方只提供了一个ImageAdapter例子,图片都是网络的

来看看官方让我们嵌入weex的时候,怎么指导的

public class ImageAdapter implements IWXImgLoaderAdapter {
  @Override
  public void setImage(String url, ImageView view, WXImageQuality quality, WXImageStrategy strategy) {
    //实现你自己的图片下载,否则图片无法显示。
  }
}

⚠️ 注意这个setImage方法,它是IWXImgLoaderAdapter提供的接口

package com.taobao.weex.adapter;
import android.widget.ImageView;
import com.taobao.weex.common.WXImageStrategy;
import com.taobao.weex.dom.WXImageQuality;

/**
 * Interface for ImageLoader. This interface works as an adapter for various image library.
 */
public interface IWXImgLoaderAdapter {

  void setImage(String url, ImageView view, WXImageQuality quality, WXImageStrategy quality);
}

这是weex SDK(android) 里类的代码:
我们关注四个参数url-view-quality-quality

再来看看我们weex内建的组件的属性:

  1. class 文档说明必须申明宽高,所以可以在vue的<style></style>部分申明
  2. style 相当于内联CSS,可以直接设置宽高
  3. src 我们最需要关注的属性,标明图片来源
  4. placeholder 占位图,加载图片需要时间特别是网络图,所以用本地图做占位是一个需求
  5. resize 图片的填充模式

那我们看看原生端,WXImage这个类的核心部分

//填充模式选择
@WXComponentProp(name = Constants.Name.RESIZE_MODE)
  public void setResizeMode(String resizeMode) {
    (getHostView()).setScaleType(getResizeMode(resizeMode));
  }

  private ScaleType getResizeMode(String resizeMode) {
    ScaleType scaleType = ScaleType.FIT_XY;
    if (TextUtils.isEmpty(resizeMode)) {
      return scaleType;
    }

    switch (resizeMode) {
      case "cover":
        scaleType = ScaleType.CENTER_CROP;
        break;
      case "contain":
        scaleType = ScaleType.FIT_CENTER;
        break;
      case "stretch":
        scaleType = ScaleType.FIT_XY;
        break;
    }
    return scaleType;
  }

同样的还有:

  @WXComponentProp(name = Constants.Name.SRC)
  @WXComponentProp(name = Constants.Name.RESIZE)

这里@WXComponentProp是weex开发自定义组件的注解,后续会讲怎么自定义component,@WXComponentProp就是起到获取标签属性的作用。

好了我们回到ImageAdapter

url就是我们的图片路径,可以是安卓SD卡里的,可以是mipmap(drawable)里的,也可以是assets里的,当然更可以是网络图片,带http://这类的,(笑

这里我们以Picasso为例子:

Picasso.with(Context).load(uri).into(view,[callback])

在setImage方法里,我们可以对url做一些处理,Picasso能接受哪些路径参数呢?

  1. mipmap(drawable) 参数是int类型
  2. assets 参数string类型,格式是'file:///android_asset/your.png'
  3. 网络 参数string 格式是正常的URL链接
  4. sdcard 暂时没有去了解

quality这个setImage参数主要是控制图片质量

public enum WXImageQuality {

  ORIGINAL,

  LOW,

  NORMAL,

  HIGH
}

Strategy这个setImage参数主要是对图片做一些剪裁和blur

public class WXImageStrategy {

  /**
   * Whether to clip image. The default value is false.
   */
  public boolean isClipping;

  /**
   * Whether to sharp the image. The default is false.
   */
  public boolean isSharpen;

  /**
   * The blur radius of the image. [0,10],0 means no blur.
   * */
  public int blurRadius;

  public String placeHolder;

  public ImageListener getImageListener() {
    return imageListener;
  }

  public void setImageListener(ImageListener imageListener) {
    this.imageListener = imageListener;
  }

  ImageListener imageListener;

  public interface ImageListener{
    public void onImageFinish(String url,ImageView imageView,boolean  result,Map extra);
  }
}

weex-eleme的图片加载代码

   //没有设置图片路径,也就是src参数为空,直接退出
     if(TextUtils.isEmpty(url)) return;

  //让加载图片的任务跑在UI线程  当然也可以不用这样
    WXSDKManager.getInstance().postOnUiThread(new Runnable() {
      @Override
      public void run() {
        if(view==null||view.getLayoutParams()==null){ return;}

    //这里给我们启示,我们可以为了不暴露图片cdn,可以在这里做处理
   //比如 src是xx.png  这里处理成http://www.yourcdn.com/xx.png
   //之所以这样是因为原生代码反编译可以混淆,但是JS是暴露的,可以直接拿到
        String temp = url;
        if (url.startsWith("//")) {temp = "http:" + url; }

        if (view.getLayoutParams().width <= 0 || view.getLayoutParams().height <= 0) {return; }

     //比如你做的是电商,这里可以使用本地的图片当作占位图,等待网络图下载✅
        if(!TextUtils.isEmpty(strategy.placeHolder)){
          Picasso.Builder builder=new Picasso.Builder(WXEnvironment.getApplication());
          Picasso picasso=builder.build();
          picasso.load(Uri.parse(strategy.placeHolder)).into(view);
          view.setTag(strategy.placeHolder.hashCode(),picasso);}

      //这里是核心,本地图加载这句代码就搞定啦
        Picasso.with(WXEnvironment.getApplication()).load(temp)
                .into(view, new Callback() {
                  @Override
                  public void onSuccess() {
                    if(strategy.getImageListener()!=null){
                      strategy.getImageListener().onImageFinish(url,view,true,null);
                    }

                    if(!TextUtils.isEmpty(strategy.placeHolder)){
                      ((Picasso) view.getTag(strategy.placeHolder.hashCode())).cancelRequest(view)
                ;}}
                  @Override
                  public void onError() {
                    if(strategy.getImageListener()!=null){
                      strategy.getImageListener().onImageFinish(url,view,false,null); 
                }} }); }},0);
  }

这里给个vue方面的例子:

<template>
        <div class="cart_wrapper" @click="changeCart">
                <div v-if="showcart">
                    <image class="cart_image" :src="cart_active_path"></image>
                </div>  
                <div v-if="!showcart">
                    <image class="cart_image" :src="cart_inactive_path"></image>
                 </div>   
        </div>
</template>

<script>
    export default {
        data(){
            return {
                cart_image_path:'file:///android_asset/cart/cart_inactive_png',
                cart_active_path:'file:///android_asset/cart/cart_active.png',
                cart_inactive_path:'file:///android_asset/cart/cart_inactive.png',
                showcart:true
            }
        },
        methods:{
            changeCart(e){
                   this.showcart = this.showcart ? false : true;
            }
        }
    }
</script>

<style scoped>
    .cart_wrapper{
        position: absolute;
        bottom: 15px;
        left: 20px;
        width:140px;
        height:140px;
    }
    .cart_image{
        width:140px;
        height:140px;
    }
</style>

总结下图片的加载,就是实现下setImage方法,不知道怎么加载本地图的同学👨‍🎓肯定是不知道:src的属性路径字符串怎么写,这里就需要你看看Picasso(安卓)的使用说明,iOS我不清楚不过应该是类似的,主要问题是路径字符串格式大家不清楚,总之还是蛮简单的。希望对你有帮助。

Hot Reload! 我想改完代码就能看界面效果!

相信使用过React Native的开发者一定熟悉RN的摇一摇刷新界面

做GUI应用开发,最简单也是最烦躁的工作就是绘制用户UI界面,我们都想写完代码就看界面效果,提高开发效率,把时间花在非界面部分

weex怎么做到实时刷新呢?

我们来看下

weex create weex-demo

生成的项目中的webpack.config.js

{
    "name": "weex",
    "version": "1.0.0",
    "description": "A weex project",
    "main": "index.js",
    "scripts": {
        "start": "npm run serve",
        "build": "webpack",
        "build_plugin": "webpack --config ./tools/webpack.config.plugin.js --color",
        "dev": "webpack --config webpack.config.js --watch -d",
        "serve": "webpack-dev-server --config webpack.dev.js --watch --open"
    },
    "keywords": [
        "weex"
    ],
    "author": "",
    "license": "MIT",
    "dependencies": {
        "fs-extra": "^4.0.1",
        "vue": "^2.4.3",
        "weex-html5": "^0.4.1",
        "weex-vue-render": "^0.12.21"
    },
    "devDependencies": {
        "babel-core": "^6.21.0",
        "babel-loader": "^6.2.4",
        "babel-plugin-add-module-exports": "^0.2.1",
        "babel-plugin-transform-runtime": "^6.9.0",
        "babel-preset-es2015": "^6.9.0",
        "babel-runtime": "^6.9.2",
        "css-loader": "^0.26.1",
        "html-webpack-plugin": "^2.30.1",
        "ip": "^1.1.5",   //这是用来控制IP的
        "raw-loader": "^0.5.1",
        "script-ext-html-webpack-plugin": "^1.8.5",
        "vue-loader": "^12.2.0",
        "vue-template-compiler": "^2.4.3",
        "webpack": "^2.2.1",
        "webpack-dev-server": "^2.4.2", //开发时当作临时服务器
        "webpack-merge": "^4.1.0",
        "weex-loader": "^0.5.3"
    },
    "optionalDependencies": {
        "ios-deploy": "^1.9.0"  //打包ipa
    }
}

注意这句脚本,开启了服务器,并监听我们的文件更改

"serve": "webpack-dev-server --config webpack.dev.js --watch --open"

5e69ac5cf4cf6070a78070c2b408aacd

⚠️最好不要使用cnpm或者yarn

官方推荐使用weex-playground,然而

在之前的文章 我们介绍了weex-ui,看到👇下面这句话

Try it with Fliggy(阿里飞猪)、Taobao(淘宝)、Tmall(天猫)、Weex Playground or any browsers now!

让我们用淘宝app扫码试试:

所以你手机里的阿里飞猪手机淘宝天猫app都可以用来开发界面啦,至此我们的热更新就实现了,还是挺简单的。

如果本文对你有帮助,请记得star项目,非常感谢🙏

写给安卓开发工程师的weex开发指南,iOS工程师可以参考

为什么是安卓,不是iOS?

本人是前端,略懂安卓,因为object-c语法晦涩所以iOS知识基本为0

什么姿势开始?weex-toolkit? hybird?

根据市面上已经做出来的产品或者demo来看,weex-toolkit📦的app性能太差,hybrid渐进的引入效果还不错,比如已经面向用户的【极客时间】app 链接

hybrid_step_01

使用Android Studio新建一个项目,取个名字,然后配置build.gradle

apply plugin: 'com.android.application'
android {
    compileSdkVersion 23
    buildToolsVersion '27.0.1'

    defaultConfig {
        applicationId "com.weex.sample"
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        /**
         * 必须加,否则64位手机无法加载so文件
         */
        ndk {
            abiFilters "x86"
            abiFilters "armeabi"
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:recyclerview-v7:23.4.0'
    compile 'com.android.support:support-v4:23.4.0'
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.alibaba:fastjson:1.1.45'
    compile 'com.taobao.android:weex_sdk:0.10.0@aar' //请使用最新的SDK版本
    compile 'com.squareup.picasso:picasso:2.5.2' //图片库也可以是glide等
    testCompile 'junit:junit:4.12'
}

实现图片下载接口,初始化时设置,这里先不讲本地图片,网络图片,等加载的问题
文件路径一般是 ../app/src/main/java/com.xxx.sss/ImageAdapter.java

package com.weex.sample;
import android.widget.ImageView;
import com.taobao.weex.adapter.IWXImgLoaderAdapter;
import com.taobao.weex.common.WXImageStrategy;
import com.taobao.weex.dom.WXImageQuality;
/**
 * Created by iChenLei on 17/12/22.
 */
public class ImageAdapter implements IWXImgLoaderAdapter {
  @Override
  public void setImage(String url, ImageView view, WXImageQuality quality, WXImageStrategy strategy) {
    //实现你自己的图片下载,否则图片无法显示。
  }
}

hybird_step_02

很重要的初始化步骤,在MainApplication里面初始化我们的WXSDKEngine

package com.weex.sample;
import android.app.Application;
import com.taobao.weex.InitConfig;
import com.taobao.weex.WXSDKEngine;
/*** 
注意要在Manifest中设置android:name=".WXApplication" 
要实现ImageAdapter 否则图片不能下载 
gradle 中一定要添加一些依赖,否则初始化会失败。 
*/
public class WXApplication extends Application { 
   @Override  public void onCreate() {    
             super.onCreate();     
             InitConfig config=new InitConfig.Builder().setImgAdapter(new ImageAdapter()).build();    
             WXSDKEngine.initialize(this,config);  
}}

hybrid_step_03

是不是想说这不是weex官网给的嵌入安卓教程么,复制粘贴有意思?NO NO NO,前面确实是一样的,下面我们就要来一个☝️不一样的!

这次我们将要使用viewpager做页面切换,RadioGroup实现BottomNavigation,效果如下:

代码详见该项目源码

        ViewPager viewpager = (ViewPager)findViewById(R.id.fragment_master);
        List<Fragment> list = new ArrayList<Fragment>();
        list.add(TestFragment.newInstance("home.js"));
        list.add(TestFragment.newInstance("web.js"));   //这里可能会疑问,这是啥?
        FragmentPagerAdapater fpa = new 
        FragmentPagerAdapater(getSupportFragmentManager(),list);
        viewpager.setAdapter(fpa);

我们主要需要实现Fragment渲染weex,当然还需要实现一些借口,因为篇幅有限这里省略

public class TestFragment extends Fragment implements IWXRenderListener {

    //JS来源 可以是本地 也可以是服务器端
    private String mBundleUrl;
    //用来装载weex页面的容器
    private FrameLayout rootView;
    //weexsdk实例
    private WXSDKInstance mWXSDKInstance;

    public TestFragment(){}

    //这里就是我们的newInstance方法
    public static TestFragment newInstance(String url) {
        Bundle args = new Bundle();
        TestFragment fragment = new TestFragment();
        args.putString(WXSDKInstance.BUNDLE_URL,url);
        fragment.setArguments(args);
        return fragment; //我们要的是fragment
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = View.inflate(getActivity(), R.layout.weex_test,null);
        rootView = (FrameLayout)view.findViewById(R.id.fragment_test);

        mBundleUrl = getArguments() != null ? getArguments().getString(WXSDKInstance.BUNDLE_URL) : null;

        mWXSDKInstance = new WXSDKInstance(getActivity());
        mWXSDKInstance.registerRenderListener(this);
        mWXSDKInstance.render("weex fragment test", WXFileUtils.loadAsset(mBundleUrl,getActivity()),null,null, WXRenderStrategy.APPEND_ASYNC);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        if (rootView.getParent() != null) {
            ((ViewGroup) rootView.getParent()).removeView(rootView);
        }
        System.out.print("[chenlei-weex]  What happened? ");
        return rootView;
    }

    @Override
    public void onViewCreated(WXSDKInstance mWXSDKInstance, View view) {
       //这句代码很重要,将我们渲染的weex view加载到FrameLayout里面
        rootView.addView(view);
        System.out.print("[chenlei-weex] Add view successful?");
    }
}

致此我们就不需要安卓开发工程师了(开除!😊),当然是开玩笑啦,不过现在就可以利用我们的weex-toolkit写vue也就是weex界面了

hybird_step_03

开始写vue(weex)部分

xcode

我那么讨厌weex-toolkit为啥还要用它,不自己弄个webpack配置呢?答案是我们可以改造weex-toolkit,完成我们的目的。改造哪里呢?当然是webpack.config.js

const weexConfig = {
  entry: weexEntry,
  output: {
    //改造下面这句代码,将我们编译后的js输出到安卓的assets里面
    path:pathTo.join('/Users/ichenlei/code/weex/WXSample/app/src/main/assets','.'),
    filename: '[name].js'
  },
//......
}

有时候我们不想把所有的vue组件都编译,只编译页面级别的vue文件,怎么做?

 const walk = (dir) => {
    dir = dir || '.';
    //⚠️我们这里遍历入口不是src/而是src/page
    const directory = pathTo.join(__dirname, 'src/page', dir);
    fs.readdirSync(directory).forEach((file) => {
      //遍历我们的page页面
  }
  // Generate an entry file before writing a webpack configuration
walk();

我们的src文件夹结构如下
-----src
|----page
|----source

最后这样我们可以利用webpack --watch模式和Android Studio的instant run来达成伪Hot Reload(官方也没有提供Hot Reload,这里无比想念React Native,对比下简直不要太棒!

路由用vue-router?浅谈如何解决Tabbar这个刚需

我想找到最高效的路由(Tabbar)方案

很多从vue开发转到weex的开发者,都会先尝试vue-router,殊不知web环境和原生环境差太多,react-native也不使用react-router呀!RN有自己的react-navigation,但是weex怎么办呢

先看看使用vue-router的作品

weex-yanxuan-demo


可能大家觉得做的很不错呀,但是实际run起来,页面切换卡爆。
在安卓上表现只能说更糟糕

所以哪里能找到完美的解决方案啦?

⚡️ 我只很遗憾的告诉你,最好写原生代码,毕竟我们没有react-navigation这种神器

🎁 在这之前我们可以看看阿里飞猪前端团队提供的weex-ui

    npm i weex-ui -S
<template>
  <wxc-tab-bar :tab-titles="tabTitles"
               :tab-styles="tabStyles"
               title-type="icon"
               @wxcTabBarCurrentTabSelected="wxcTabBarCurrentTabSelected">
    <!--The first page content-->
    <div class="item-container" :style="contentStyle"><text>Home</text></div>
    
    <!--The second page content-->
    <div class="item-container" :style="contentStyle"><text>Hot</text></div>
    
    <!-- The third page content-->
    <div class="item-container" :style="contentStyle"><text>Message</text></div>
    
    <!-- The fourth page content-->
    <div class="item-container" :style="contentStyle"><text>My</text></div>
  </wxc-tab-bar>
</template>

<style scoped>
  .item-container {
    width: 750px;
    background-color: #f2f3f4;
    align-items: center;
    justify-content: center;
  }
</style>
<script>
  import { WxcTabBar, Utils } from 'weex-ui';
 
  // https://github.com/alibaba/weex-ui/blob/master/example/tab-bar/config.js 
  import Config from './config'

  export default {
    components: { WxcTabBar },
    data: () => ({
      tabTitles: Config.tabTitles,
      tabStyles: Config.tabStyles
    }),
    created () {
      const tabPageHeight = Utils.env.getPageHeight();
      const { tabStyles } = this;
      this.contentStyle = { height: (tabPageHeight - tabStyles.height) + 'px' };
    },
    methods: {
      wxcTabBarCurrentTabSelected (e) {
        const index = e.page;
        // console.log(index);
      }
    }
  };
</script>

我们查看weex-ui的tabbar源码,这里我们省略次要代码。看看飞猪团队怎么做的,看到 weex.requireModule('animation') 我们就明白了飞猪做tabbar的套路和web端是一样的,利用动画偏移我们的组件,加上动画效果的到tabbar的效果。但是这里问题来了,react-navigation可以懒加载第2,3,4位置的tabbar-page,weex-ui显然是不行的,如果是比较轻量级的app,勉强接受,不过显然我们想要做更多的控制。

const animation = weex.requireModule('animation');
export default {
    props: {},
    data: () => ({
      currentPage: 0,
      translateX: 0
    }),
    created () {
      //省略内容
    },
    methods: {
    //省略内容
      _animateTransformX (page, animated) {
        const { duration, timingFunction } = this;
        const computedDur = animated ? duration : 0.00001;
        const containerEl = this.$refs[`tab-container`];
        const dist = page * 750;
        animation.transition(containerEl, {
          styles: {
            transform: `translateX(${-dist}px)`
          },
          duration: computedDur,
          timingFunction,
          delay: 0
        }, () => {
        });
      }
    }
  };

c1e3b2de-a32e-491a-97e7-2ae51ee5b52d

weex-ui的用户如是说到,确实想要三端一致,我还是建议使用的。

最后推荐原生混合weex的方式,tabbar原生实现,页面使用weex 两个成功的例子

1.极客邦旗下的【极客时间app】,几十万用户量级

2.我的demo例子,具体原生tabbar混合weex怎么做。请看源码

如果对你有帮助,记得给我的项目star,谢谢

weex 与 原生混合

你好,我有个项目,app在主界面有2个菜单,分别跳转到2个不同的商城界面。这2个商城都是使用vue开发的。每个商城界面都包含很多的子页面或者跳转到其他的页面。
这个app使用weex与原生混合开发是否可行?
每个商城都有自己的router。

打开weex的正确姿势到底是什么?

Chapter01--初识weex,纯粹是为了竞赛

第一次接触weex,是看到学校论坛里的weex校园开发比赛,脑子热就参加了。时间是2016年12🈷️

weex作为阿里巴巴集团年度重量级开源项目,引起业界重大关注。在开元不到2个月的时间内,github的star数目前已经突破了5300+,累计github issues讨论500+,累计article50+。weex作为一个开源项目,需要更多的开发者涌入到开源社区,积极贡献社区,特举办本次竞赛。

看看当时的介绍,社区讨论还是很热烈,官方开发还是热情,现在真是冷冷清清,可能KPI完成了(笑

Chapter02--开始写weex,我差点疯了

官方给出的开启方式

$ npm install -g weex-toolkit
$ weex -v //查看当前weex版本
weex update weex-devtool@latest //@后标注版本后,latest表示最新

之后就可以开始初始化我们的项目

$ weex create awesome-project

当我们按照教程弄完后,打开浏览器,傻眼了! Nothing to show ! (笑
现在应该修复了吧,不清楚

是的,不得不说这对新手太不友好了,太伤信心!
原因很简单,weex.html的js引入路径错了,将weex-vue-render/index.js改为weex-vue-render/dist/index.js就行。真是太无语了

好吧,改完继续:
ub 2d1qre52ff gk 0w87
千万别用cnpm安装依赖,yarn也不要用!
网页也可以看效果了,那么真机上跑一跑?ε=ε=ε=( ̄▽ ̄)

weexpack run android // or npm run android

_nr11m ade 6 d5hpzp1a k

我┗( T﹏T )┛投降好嘛?什么鬼,怎么安卓打包不了?
阿里巴巴的工程师,你一定是在逗我,alibaba-inc.com是你们内网好嘛!我们怎么访问!(′д` )…彡…彡
至此,我已经疯了,ヾ( ̄▽ ̄)ByeBye这个世界







不,我怎么能放弃,我要坚强!
我要开启正确打开姿势!(至于为什么不继续写,我才不会说这篇篇幅已经够了呢(^_^)

超棒的例子,简单介绍weex和原生混合的极客时间app

极客时间app download

极客时间是极客邦科技出品的一款 IT 内容知识服务 App,内容包含专栏订阅、极客新闻、热点专题、直播、视频和音频等多形式的知识内容,并设有陈皓专栏、徐飞专栏、洪亮...

先看看app的主要几个页面

首页 页面做的很不错

专栏

我的

开发这个app的小哥和我是好友,做的app真的很不错,建议大家尝试使用,有什么问题可以问我。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.