使用 Vue、Dcloud 开发 WebApp

2018-01-10

介绍

先看一位大佬的 移动端音乐App,来自 慕课网

打开 Chrome 控制台,使用移动端模式观看,效果更佳。

可以看到,使用 Vue 构建的单页应用,辅以 vue-router 提供的页面打开时 slide 动画,体验极佳。再使用 Dcloud 分别打包成 Android App 和 iOS App,即可一次开发,多端运行。

Dcloud 打包成 App,是使用 webview 承载 web 页面,多个页面使用多个 webview 承载,提供给开发者打开、关闭 webview 时的 slide 动画,使之有类似 Native App 的转场效果。并提供 JSBridge 桥,使 JavaScript 能够访问原生的设备功能,如打开新的 webview、存储数据、拍照、调用相册等。

我们使用 Vue 开发出单页应用,使用 Dcloud 进行打包,用一个 webview 承载。

这里我们只用到 Dcloud 提供的 调用原生、打包 功能。其他功能点 Vue 可以做得更好。

环境搭建

首先安装 Node.js, 一般我们到 Node.js中文官网 下载、安装。

安装完成之后可打开命令行工具,依次执行

1
2
node -v
npm -v

如果都出现相应的版本号,则说明安装成功。

由于 npm (node package manager) 默认源在国外,一般我们会通过执行以下命令,来使我们可以通过执行cnpm install,使用 淘宝 NPM 镜像 以提高依赖包下载速度:

1
npm install -g cnpm --registry= https://registry.npm.taobao.org

使用 vue-cli 快速构建

使用 cnpm 全局安装 vue-cli 脚手架构建工具,:

1
cnpm install vue-cli -g

之后我们将使用 vue-cli 帮助我们快速构建项目结构。

首先在命令行中,cd 进入你想要存放项目的目录,执行:

1
vue init webpack vue-project

其中 webpack 是模板名称,另有 更多的模板

我们在命令行中回答几个问题,使用 回车键 来使用默认值,Y/n 来选择是否安装,上下移动箭头并回车 来选择目标选项。以生成我们想要的项目结构,我的回答结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
vue init webpack vue-project

⠼ downloading templatecentral entry: webpack-master/

......

? Project name vue-project
? Project description A Vue.js project
? Author name <name@mail.com>
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recomm
ended) no

以上我们引入了 vue-router,使用 JavaScript Standard Style 代码规范,规范包含两空格缩进,行尾不加分号。并在项目中使用 ESLint 来进行实时提示(与 VSCode 编辑器一起使用,效果更佳)。

不直接执行npm install,因为我们之后要使用cnpm install来使用淘宝镜像来安装依赖包。

现在项目结构已经生成好了,我们根据提示,一一执行:

1
2
3
4
cd vue-project
cnpm install
npm run lint -- --fix
npm run dev

以上是我们进入项目目录,安装 package.json 文件中的依赖包,根据 ESLint 配置修复项目文件代码格式,并运行项目。

一一执行后可以看到提示:

1
Your application is running here: http://localhost:8080

打开链接,即可看到项目输出,在代码中进行修改并保存,页面即实时更新。

命令行中Ctrl + C即可退出。

生成的项目目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.
├── build // webpack 配置文件
├── config // webpack 配置文件
├── dist // npm run build 后,输出目录
├── node_modules // 依赖包放置目录
├── src // 开发者代码目录
│   ├── assets // 放置 js、css、img 文件
│   ├── components // vue 组件
│   └── router // vue-router 配置
├── static // 静态资源目录,对应 dist 下的 static
├── .babelrc // babel 配置
├── .editorconfig // 编辑配置
├── .eslintignore // eslint 忽略文件配置
├── .eslintrc.js // eslint 配置
├── .gitignore // git 提交代码时,忽略文件配置
├── .postcssrc // postcss 插件配置
├── index.html // 入口文件
├── package.json // npm 记录依赖包
└── README.md // README 文件

在此不对 npm,webpack 进行介绍,掘金上已有众多文章。

以上目录,我们需关心的主要是 src 和 dist 目录,src 是我们的代码目录。我们在开发过程中使用 ESLint 进行代码规范,开发后执行npm run dev, webpack 即可通过使用各种依赖包及配置项,将我们的代码进行打包,输出到 dist 目录。

实践推荐

ECMAScript 6 入门

Flex 布局教程:语法篇

Flex 布局教程:实例篇

VSCode编辑器

VSCode 安装插件:

  • JavaScript (ES6) snippets
  • Vetur
  • Vue 2 Snippest
  • ESLint

在 VSCode 用户设置中写入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 一个制表符等于的空格数
"editor.tabSize": 2,
// An array of language ids which should be validated by ESLint
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "vue",
"autoFix": true
},
"html"
],
// Run the linter on save (onSave) or on type (onType)
"eslint.run": "onSave",
// Turns auto fix on save on or off
"eslint.autoFixOnSave": true

这样我们可以保存文件的同时,修复代码不规范的地方。

不熟悉代码规范的同学不建议要写入上述配置.实时 lint,自行修复,有利于养成代码规范习惯。

进行开发

使用 Less

首先安装 Less 依赖,在命令行中执行:

1
2
cnpm install less --save-dev
cnpm install less-loader --save-dev

并告诉 webpack 如何编译 Less,在 webpack.base.conf.js 文件的 webpackConfig.module.rules 中添加:

1
2
3
4
{
test: /\.less$/,
loader: 'style!css!postcss!less'
}

使用组件库

Vant

Mint UI

BetterScroll

按照 Vant 文档,进行安装:

1
cnpm i vant -S

由于我们使用 Dcloud 打包成 App,文件都存放在手机存储中,而不是像 Web 到服务器请求资源,故可使用导入所有组件,免去一一引入的繁琐。

main.js 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Vue from 'vue'
import App from './App'
import router from './router'
import Vant from 'vant'
import 'vant/lib/vant-css/index.css'

Vue.config.productionTip = false
Vue.use(Vant)

/* eslint-disable no-new */
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
})

我们在 src 文件夹下,新建 views 目录,新建页面组件

1
2
3
4
5
6
7
src
└── views
├── Dingdan.vue
├── Faxian.vue
├── List.vue
├── Waimai.vue
└── Wode.vue

在 App.vue 文件中使用 tarbar 及 header(navbar) 组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<template>
<div id="app">
<van-nav-bar title="标题" rightText="按钮" @click-right="onClickRight" />

<keep-alive>
<div class="wrap">
<router-view></router-view>
</div>
</keep-alive>

<van-tabbar v-model="active">
<van-tabbar-item icon="shop" replace to="waimai">外卖</van-tabbar-item>
<van-tabbar-item icon="chat" dot replace to="dingdan">订单</van-tabbar-item>
<van-tabbar-item icon="records" info="5" replace to="faxian">发现</van-tabbar-item>
<van-tabbar-item icon="gold-coin" info="20" replace to="wode">我的</van-tabbar-item>
</van-tabbar>
</div>
</template>

<script>
export default {
name: 'app',
data () {
return {
active: 0
}
},
methods: {
onClickRight () {
this.$router.push('list')
}
}
}
</script>

<style lang="less">
@import url('./assets/css/reset.less');

html, body, #app {
height: 100%;
}

#app {
display: flex;
flex-direction: column;

.wrap {
flex: 1;
height: 100%;
margin-bottom: 50px;

overflow-y: auto;
overflow-x: hidden; }
}
</style>

并在 router/index.js 文件中,配置路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import Vue from 'vue'
import Router from 'vue-router'

import Waimai from '@/views/Waimai' // @ 是 webpack 配置的 src 的别名,见 webpack.base.conf.js 文件 alias
import Dingdan from '@/views/Dingdan'
import Faxian from '@/views/Faxian'
import Wode from '@/views/Wode'
import List from '@/views/List'

Vue.use(Router)

export default new Router({
routes: [
{
path: '/',
redirect: '/waimai'
},
{
name: 'waimai',
path: '/waimai',
component: Waimai
},
{
name: 'dingdan',
path: '/dingdan',
component: Dingdan
},
{
name: 'faxian',
path: '/faxian',
component: Faxian
},
{
name: 'wode',
path: '/wode',
component: Wode
},
{
name: 'list',
path: '/list',
component: List
}
]
})

此时 tabbar 四个选项,已经通过 vue-router,与 views 下的页面进行了映射。

我们尝试下 slide 效果,在 List.vue 文件中写入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<template>
<transition name="slide">
<div class="list">
<van-nav-bar title="标题" leftText="返回" rightText="按钮" leftArrow @click-left="onClickLeft" @click-right="onClickRight" />
<p>list</p>
</div>
</transition>
</template>

<script>
export default {
data () {
return {
}
},
methods: {
onClickLeft () {
this.$router.go(-1)
},
onClickRight () {
// this.$toast('按钮')
},
handler () {
}
}
}
</script>

<style lang="less">
.list {
position: fixed;
z-index: 100;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: #f0f0f0;

&.slide-enter-active,
&.slide-leave-active {
transition: all 0.3s;
}

&.slide-enter,
&.slide-leave-to {
transform: translate3d(100%, 0, 0);
}

}
</style>

点击 header 上的 “按钮”,即可 get 顺滑体验。

build

开发完成之后,运行

1
npm run build

即可进行打包,输出到 dist 目录下,之后我们将使用 Dcloud 对输出文件进行打包。

打包 App

Dcloud 官网 下载 Hbuilder

  1. 在 HBuilder 中新建移动App项目,选择空模板
  2. 将 dist 文件夹 放入项目目录
  3. mainfest.json 中进行配置,入口文件为 dist/index.html
  4. 使用 Hbuilder 提供的 发行/云打包 功能,打包为 App

可以参考文档:5+ App开发入门指南

Dcloud 提供给开发者调用系统功能,详见:HTML5+ 规范