用weexplus从0到1写一个app(1)-环境搭建和首页编写

说明

基于wexplus开发app是来新公司才接触的,之前只是用过weex体验过写demo,当时就被用vue技术栈来开发app的开发体验惊艳到了,这个开发体验比react native要好很多,对于我这个纯web前端来说简直不要太好!

weexplus是基于weex官方的二次开发版本,旨在解决weex官方配置麻烦、性能不好、开发体验不好等问题。weexplus框架是这边同事根据实际的项目抽离出来的开源框架,已经帮我们趟过很多坑了,具体组件用法在此不再赘述,link-放出文档。本文仅为本人视角开发一个吉他学习app的踩坑之路记录,记下以免后面再踩坑。

文章思路

文章思路

文章可能会很长,在此分几篇文章来写,先占个坑:

先看东西

app的ui界面与h5、小程序公用一套,所以做出来的界面也是基本一样,这里感谢以下杨伯伯提供的设计稿。

爱尚吉他设计稿

环境搭建

  • node环境安装(windows、mac稍有不同,具体安装自行百度即可);
  • weex环境安装(前提是必须有node环境);
$ npm install  weex-toolkit -g // -g表示全局安装,下同
  • weexplus环境的安装,weexplus工具为我们提供了很多常用的开发功能,具体详情查看weexplus文档即可;
$ npm install weexplus -g
  • 创建项目,按照官方文档用weexplus create会遇到网速很慢的问题,我这里是下载官方的boilerplate然后改名;
$ 浏览器访问 https://github.com/weexplus/boilerplate,下载压缩包得到文件boilerplate-master.zip;
$ 解压boilerplate-master.zip得到文件夹boilerplate-master;
$ cd到跟boilerplate-master平级的目录;
$ weexplus rename loveguitar com.loveguitar.23jt loveguitar;
$ cd loveguitar
$ npm install //安装依赖包
$ npm run dev
$ weexplus start //运行改命令需要另外开一个终端,运行成功后谷歌浏览器会跳出一个新页面,必须安装谷歌浏览器
$ 下载安卓apk调试包(真机扫码调试)地址 https://pan.baidu.com/s/16kJfMuyXX-Y_yhm5fHt79Q 

至此,weexplus开发环境基本搭建完毕,如果需要打包安卓、ios的话,与原生开发一样,自行百度即可解决。

项目目录结构

weexplus项目目录结构

如图为weexplus脚手架项目目录结构图,我们平常开发主要在src目录里写代码,可以看到该目录与vue项目目录结构基本差不多。

开始写代码

在写代码前可以把脚手架里无用的代码删除掉,留下component文件夹即可。先做的第一件事个人建议是依照原型或者设计稿的业务逻辑在src/busi文件夹中按照业务模块建好文件夹(以爱尚吉他为例):

爱尚吉他业务目录结构
map:琴行地图功能模块,里面分为琴行地图首页、琴行详情、琴行导航
news:文章模块,里面分为文章列表、文章详情、标签列表
search:文章搜索模块
video:视频教程模块,里面分为视频模块首页,视频列表、视频详情

写一个首页看看

子曰:“工欲善其事,必先利其器。”在写首页的代码前在此安利一款切图标注工具--蓝湖, 大大提高设计师和开发的工作效率,具体使用参见官网介绍即可http://sos.lanhuapp.com/#/

首页效果图

以上为首页的设计图,先来分析一下页面结构,看看哪些可以复并且可以封装为公共组件。如图所示可以分为如下几个模块:

1(banner模块),在componet文件夹下新建my-banner.vue文件
2(模块标题),在componet文件夹下新建my-title.vue文件
3(菜单模块),在componet文件夹下新建my-nav.vue文件
4(文章列表模块两个类型)在componet文件夹下新建news-item.vue文件
模块分析

按照vue的规范分别在componet文件夹下新建my-banner.vuemy-title.vue·my-nav.vuenews-item.vue四个文件。

轮播图组件my-banner.vue封装

//src/component/my-banner.vue
<template>
  <div class="banner-box">
    <slider class="slider" :style="{'height':height,'width':width}" interval="1500" @change="onchange">
      <div class="frame" :style="{'height':height,'width':width}" v-for="(item,index) in bannerList" :key="index">
        <image :style="{'height':height,'width':width}" class="image" resize="cover" :src="item.pic" />
      </div>
      <indicator class="indicator"></indicator>
    </slider>
  </div>
</template>

这里用到了weex官方的sliderindicator组件,具体的属性用法参见weex文档slider用法。考虑到轮播图的尺寸不固定,在组件中暴露height(图片高度)width(图片宽度)两个属性提供给父组件传入。

在此注意几个问题:
1.注意图片标签的写法与web中使用vue稍有不同,web中是img,在weex中用image;
2.weex中不支持padding、margin、border属性值的简写,如不支持padding:10px
和border:1px solid #dcdcdc这样的写法。

标题组件my-title.vue的封装

//component/my-title.vue
<template>
  <div class="about-title">
    <text class="title-text">{{title}}</text>
    <div v-if="url!=null&&url!=''" @click="goto(url)" class="more">
      <text>更多</text>
      <image src="http://hurely.u.qiniudn.com/20180601152782173548498.png" class="form-icon-r"/>
    </div>
  </div>
</template>

样式方面没什么好说的,考虑到有些标题是没有跳转更多的,需要做一下判断为空的情况。

在此注意几个问题:
1.注意在weex中文字需要使用text标签,考虑到后续可能会移植为web或者小程序,
text标签最好用class来控制样式;
2.weex默认支持flex布局,考虑到后续可能会移植为web或者小程序,在需要
用到flex布局的地方写上display:flex属性。

菜单组件my-nav.vue的封装

//componet/my-nav.vue
<template>
  <div class="nav">
    <div class="nav-item" @click="goto(item.url)" v-for="(item,index) in navList" :key="index">
      <image class="nav-icon" :style="{'width':width,'height':height}" :src="item.src" />
      <text class="nav-text">{{item.text}}</text>
    </div>
  </div>
</template>

样式方面没什么说的,考虑到会跳转不同的页面,注意在跳转方法里做判断即可。

列表组件news-item.vue的封装

//componet/news-item.vue
<template>
  <div v-if="type==1">
    <div class="item-box" @click="click">
      <div class="item-left">
        <text class="left-text">{{item.title}}</text>
        <div class="left-line"></div>
        <text class="left-time">{{item.pubdate}}</text>
      </div>
      <div class="item-right">
        <image :src="item.pic.src" mode="aspectFill" class="litpic" />
      </div>
    </div>
  </div>
  <div class="item-box2" v-else-if="type==2"  @click="click">
    <image :src="item.pic.src" mode="aspectFill" class="litpic2" />
    <text class="box2-text">{{item.title}}</text>
  </div>
</template>

可以看到我标记4的地方有两处,在组件里加一个type作为判断即可,列表点击事件通过this.$emit传递到父组件调用。至此首页四个公共组件封装完毕,下面开始编写首页代码。

首页编写

//busi/home.vue
<template>
  <div class="app">
    <scroller>
    <banner-item :bannerList=bannerList></banner-item>
    <div class="home-nav border">
      <title-item title="热门栏目" url=""></title-item>
      <div class="nav-items">
        <div class="nav-item" v-for="(item,index) in navList" :key="index" @click="goto(item.url)">
          <image mode="aspectFit" :src="item.pic" class="nav-icon"/>
          <text class="nav-text">{{item.title}}</text>
        </div>
      </div>
    </div>
    <div class="home-news border">
      <title-item title="热门文章" url="../news/list"></title-item>
      <div v-for="(item,index) in newsItems" :key="index">
        <homenews-item
          type=1
          @click="gotonews(item.id)"
          :item="item"
        ></homenews-item>
      </div>
    </div>
    <title-item title="热门专辑" more="../video/index"></title-item>
    <div class="hot-box">
      <video-item
          v-for="(ite,index) in videoitems" :key="index"
          @click="gotovideo(ite)"
          :item="ite"
          type=2
        ></video-item>
    </div>
    <support-item></support-item>
    </scroller>
  </div>
</template>

样式方面无需说明,这里说一下数据请求的封装。分别在busi/util文件夹新建文件request.jsapi.js(非必须),其中request.js基于fly库封装(考虑到weex官方的数据请求库有点坑,在此弃用),便于管理后端接口建议在api.js文件中统一管理。

以下为fly.js库的封装,具体使用参照fly.js官方文档,如果需要增加登录拦截什么的,可以在fly.interceptors.request.use中增加即可。

//request.js
var Fly = require("flyio/dist/npm/weex");
var fly = new Fly;

//bmob云数据库的配置,非必须
const bmobConfig = {
  applicationId:'applicationId',
  restApiKey:'restApiKey',
  secretKey:'secretKey',
  masterKey:'masterKey'
}

var progress = weex.requireModule("progress")
var modal = weex.requireModule("modal")
//添加请求拦截器
fly.interceptors.request.use((request)=>{
  progress.show();
  //给所有请求添加自定义header
  request.headers["X-Tag"]="flyio";
  request.headers['X-Bmob-Application-Id'] = bmobConfig.applicationId;
  request.headers['X-Bmob-REST-API-Key'] = bmobConfig.restApiKey;
  request.headers['Content-Type'] = 'application/json';  
  //可以显式返回request, 也可以不返回,没有返回值时拦截器中默认返回request
  return request;
})

//添加响应拦截器,响应拦截器会在then/catch处理之前执行
fly.interceptors.response.use(
  (response) => {
      //只将请求结果的data字段返回
      progress.dismiss();
      return response.data
  },
  (err) => {
      //发生网络错误后会走到这里
      progress.dismiss();
      //return Promise.resolve("ssss")
  }
)

module.exports  = fly;

以下为后端接口统一管理文件api.js

/**
 * @description 请求地址
 */

const baseUrl = 'http://baidu.com/';
const urls = {
  videoList:'videoList',
  videoContent:'videoContent',
  amapGetaddress:'amapGetaddress',//高德地图经纬度转地址
  home: baseUrl + 'home',//首页
  categoryIndex:baseUrl+'categoryIndex',//菜单分类 type=list显示
  categoryList:baseUrl+'categoryList',//参数cid通过categoryIndex获得 page为分页
  tagList:baseUrl+'tagList',//标签列表&id=7656&page=1
  articleDetails:baseUrl+'articleDetails',//文章详情
  about:'about',//关于
  search:baseUrl+'search',//&q=周杰伦&page=1
};
export default urls

数据请求实例,用过axios库的应该很熟悉这种写法

getData() {
    const that = this;
    fly.get(apis.home, {})
    .then(res => {
        let bannerList = [];
        JSON.parse(res).article_hot.data.map((item,index)=>{
            item.pic = item.pic.src;
            bannerList.push(item)
        })
        that.bannerList = bannerList;
        that.newsItems = JSON.parse(res).article_list;
    })
    .catch(error => {});
}

参考文档

一点私货

基于同一套ui开发出来的爱尚吉他微信小程序版已经上线喜欢弹吉他的小伙伴可以关注一波

爱尚吉他微信小程序二维码
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容