移动APP介绍

移动APP

能够运行在移动端中的应用程序

背景

Wap

早期手机浏览的网站,因为手机屏幕小,处理能力小,所以需要特殊格式的网页(简陋)主要展示内容,不侧重功能

Web App(网页应用)

所有的页面资源全都存储于服务器中,受限于网络 BS模式

侧重于功能,基于HTML5、JS、CSS开发实现特定功能的应用,依赖于浏览器

网页(web)是电脑访问,web App就是web是电脑浏览器的网页,app是移动设备的一个应用软件,他们加起来就是一个能在电脑用的软件又能在移 动设备端安装的软件,支持多平台运行。

Web App的开发几乎完全构建在Webview的基础之上

WebView(网络视图)能加载显示网页,可以将其视为一个浏览器。它使用了WebKit渲染引擎加载显示网页

优点:

开发成本低、不用下载客户端、更新无需通知用户、不需要手动升级、跨平台

可以运行在 PC、安卓、iOS、Pad 等各种终端

缺点:

用户体验稍差、无法获取系统级别的通知或提醒、设计受限制诸多

Native App(原生应用)

所有的资源几乎都是存储于本地的(安装的程序就是资源,应用的资源都是从本地获取) CS模式

是一种基于智能手机本地操作系统如IOS、Android、WP并使用原生程式编写运行的第三方应用程序,也叫本地app

优点:

完美的用户体验、性能高且稳定、访问本地资源(通讯录,相册)、拥有系统级别的贴心通知或提醒

缺点:

不能跨平台、开发成本高(不同平台有不同的开发语言和界面适配)、维护成本高(例如一款App已更新至V5版本,但仍有用户在使用V2, V3, V4版本,需要更多的开发人员维护之前的版本)、更新缓慢,根据不同平台,提交–审核–上线 等等不同的流程,需要经过的流程较复杂

Hybrid App(混合应用)

(混合模式移动应用)是指介于Web App、native-app这两者之间的app,兼具“Native App良好用户交互体验的优势”和“Web App跨平台开发的优势”

优点:

跨平台、性能与原生差别不大、小更新无需重装

缺点:

不适合开发游戏,受限于技术,网速,等等很多因素

Facebook

Facebook在React Native里引入了一种跨平台的基于CSS的布局系统

移动App开发

主流移动终端系统:Android、iOS

移动App开发方式

  • Native : 安卓(Java)、苹果(Object C、Swift)
  • Web : JavaScript + HTML + CSS 等相关技术
  • Hybrid : JavaScript + HTML + CSS 等相关技术,配合原生开发语言

前端混合App框架

React.js 和 React-Native

Vue.js 和 Weex

Angular.js 和 Ionic

1
2
3
4
5
onic是一款基于angularjs的html5移动app开发框架,打包功能是基于Phonegap/Cordova的
Phonegap就是一款可以打包并且可以让js调用原生的移动app框架,可以独立开发app
phonegap与cordova 移动开发平台:
Cordova是贡献给Apache后的开源项目,是从PhoneGap中抽出的核心代码,是驱动PhoneGap的核心引擎。你可以把它们的关系想象成类似于Webkit和Google Chrome的关系。---摘自百度百科

HBuilder + MUI

  • 认识HTML5+
    • h5+是一个产业联盟,它有一些互联网成员,专门在中国推广H5
    • H5+的js库操作浏览器的组件,也就是可以调用浏览器组件的方法,由浏览器去调用手机的API
    • html5不具备操作移动端的API
  • HTML5+ 说明
  • MUI开发

vuex

vuex

State

保存的状态,公有数据

Getters

提供获取数据的方式

Mutations

改变-改变数据

Actions

行为,封装调用改变的发生

1
2
3
Action 通过 store.dispatch 方法触发:
store.dispatch('increment')

Modules

模块(以上配置的封装)

Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割

vuex

当需要CRUD的时候

1-在程序内调用actions->添加用户行为

2-调用添加用户的mutations里面的某一个改变行为

3-操作数据的方式改变state.属性

getters(获取数据)

state.xxx也可以获取数据,但是不推荐

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
56
57
58
59
60
61
//main.js
import App from './app2.vue';
//引入vue
import Vue from 'vue';
//引入vuex
import Vuex from 'vuex';
//安装插件 未来this.$store能够拿到总体的仓储对象 该对象可以直接.state拿数据
Vue.use(Vuex);
let userOptions = {
state: { //数据
users: [{ name: 'jack', age: 18 }, { name: 'rose', age: 17 }]
},
mutations: { //发生改变CRUD
add(state, data) {
state.users.push(data);
},
edit(state, data) {
state.users[data.index].name = data.name;
},
del(state, index) {
state.users.splice(index, 1);
}
},
actions: { //行为,代码中会涉及到业务
addUser({ commit }, user) {
//content 相当于$store也可以提交.commit .state
commit('add', user)
},
editUser({ commit }, user) {
commit('edit', user);
},
delUser({ commit }, index) {
commit('del', index);
}
},
getters: { //获取数据,结合computed来一起使用
users(state) {
return state.users;
}
}
}
//配置仓储的数据
let store = new Vuex.Store({
modules: {
//模块名:模块配置
userOptions,
}
});
//将该对象配置进Vue实例options中
new Vue({
el: '#app',
store,
render: c => c(App)
})
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
//app.vue
<template>
<div>
<input type="text" name="" v-model="user.name">
<input type="text" name="" v-model="user.age">
<button @click="addUser">添加用户</button>
<ul>
<li v-for="(user,index) in getUsers" :key="index">
{{user.name}} {{user.age}} <a @click="edit(index)">编辑我</a> <a @click="del(index)">删除我</a>
</li>
</ul>
<!-- 模块方式以后,只有单独获取state的数据需要额外增加模块名 -->
{{$store.state.userOptions.users}}
</div>
</template>
<script>
export default {
data() {
return {
user: {} //用来添加用户
}
},
methods: {
addUser() {
//分发,有时处理异步任务的时候,$store直接commit,该行为无法完成记录,这种方式是ok的
this.$store.dispatch('addUser', this.user);
},
del(index) {
this.$store.dispatch('delUser', index);
},
edit(index) {
//编译的时候,由于添加或者删除元素了,索引就会不准确,最好使用id来编辑
this.$store.dispatch('editUser', {
index,
name: '已经修改'
});
}
},
computed: {
getUsers() { //结合computed优雅的获取数据
return this.$store.getters.users;
}
}
}
</script>
<style>
</style>

vue处理bootstrap

vue处理bootstrap

bootstrap依赖全局$需要声明全局的,webpack默认将$作为局部的

webpack.config.js中配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const webpack = require('webpack');
// 处理.eot .woff2 .woff后缀的文件
test: /\.(jpg|ttf|svg|png|gif|eot|woff2|woff)$/,
loader: 'url-loader?limit=4096'
plugins: [
// 声明全局对象的插件
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
],

main.js中引入bootstrap

1
2
3
import bootstrap from 'bootstrap';
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap/dist/css/bootstrap-theme.css'

ES6导入导出

ES6导出导入

default

1
2
3
4
5
6
import 对象 from 相对路径文件;
import cal12 from './test_import_cal.js'; //export default cal2;
//默认导入出,导入值到变量cal12中,从./xxx.js来
//import 变量名 from '路径'; export default {name:'jack'};
//导入一个值
// console.log(cal12);

声明式导入(按需加载)

加载文件还是整体加载,只取其中一个部分

1
2
3
4
5
6
7
import { hand } from './person.js'; // export let hand = '小嫩手';
import { foot } from './person.js'; // export let foot = '小嫩脚';
import { head } from './person.js'; // let head = '大头'; export {head};
console.log(hand);
console.log(foot);
console.log(head);

全体导入导出

1
2
3
4
5
6
7
8
9
10
11
//固定 固定 可变 固定 固定
import * as person from './person.js'; //所有导出都能拿
console.log(person);
//注意是事项
function test(){
import * as person from './person.js'; //所有导出都能拿
console.log(person);
}
test();

vue插件

vue插件和框架

mint-ui 框架

移动端

构建界面

使用方式

  • 1:下载 npm i mint-ui --save
  • 2:在main.js文件中 引入mint-ui 及css
  • 3:安装插件(Vue.use(mint-ui的对象))
1
2
3
4
5
6
7
//1:引入对象
import MintUi from 'mint-ui';
//2:引入其css
import 'mint-ui/lib/style.css';
//安装插件
Vue.use(MintUi); // 执行内部,就是多次注册全局组件

mui 框架

移动端

构建界面

axios 插件

i18n

vue-i18n

  • internationalization 国际化
  • 在你项目完善以后,涉及到可能需要给歪果仁使用
  • vue中的插件
  • vue-i18n
    • 1:下载 npm i vue-i18n --save
    • 2:引入对象并安装插件
    • 3:创建i18n对象、配置:默认语言(locale)、数据(messages)
    • 4:将实例交给vue
    • 5:显示(在模板template ) $t
  • 通过下拉列表(动态的)。改变。变更页面中显示的数据

const messages = {

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
'zh-cn': {
name: 'vue-i18n',
desc: '基于VueJS的国际化多语言切换组件',
lang: '中',
msg1: '1.支持表单元素属性',
msg2: '2.支持模板参数替换',
msg3: '3.支持多级对象',
msg4: '4.支持刷新后保存语言状态'
},
'en': {
name: 'vue-i18n',
desc: 'Internationalization plugin of VueJS',
lang: 'EN',
msg1: '1.Support Form element properties',
msg2: '2.Support Template parameter substitution',
msg3: '3.Support multi-level objects',
msg4: '4.Support save the language status'
}

}

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
template>
<div>
显示数据区域:$t transform
<hr/>
{{ $t('name') }} <br/>
{{ $t('desc') }} <br/>
{{ $t('lang') }} <br/>
{{ $t('msg1') }} <br/>
{{ $t('msg2') }} <br/>
{{ $t('msg3') }} <br/>
{{ $t('msg4') }}
<select @change="change" v-model="selected">
<option v-for="(language,index) in languages" :key="index" :value="language.value">{{language.viewName}}</option>
</select>
</div>
</template>
<script>
export default {
data(){
return {
data:[],//返回的是数组
selected:'', //下拉列表的值
languages:[
{
viewName:'请选择',
value:''
},
{
viewName:'中文',
value:'zh-cn'
},{
viewName:'english',
value:'en'
}]
}
},
created(){
},
methods:{
change(){
console.log(this.selected);
this.$i18n.locale = this.selected;
}
}
}
</script>

element-ui 框架

PC端

webpack使用非模块化

webpack使用非模块化

如何加载非模块化的代码

exports-loader

1
2
3
4
5
6
7
8
9
10
11
12
13
// text.js
var test1 = 'abc';
var test2 = function() {
console.log('111')
}
-----------------------------------------------
// main.js
let test1 = require('exports-loader?test1!./test.js'); //变量/变量所在文件的目录
console.log(test1);
let test2 = require('exports-loader?test2!./test.js');
console.log(test2);

购物车

购物车

增删改查

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
let goodsTools = {};
//初始化存储商品的对象
// let prods = {88:1};
let prods = JSON.parse(window.localStorage.getItem('prods'))||{};
goodsTools.addOrUpdate = function(goods){ // -> {id:88,num:1 }
//判断当前id是否存在
if(prods[goods.id]){ //goods.id -> 88 /89
prods[goods.id] += goods.num;
}else{
//当前id不再对象的key中,也就是没有存储过
prods[goods.id] = goods.num;
}
//要让内存的对象与本地存储保持同步
this.save(prods);
}
//删除 {88:1,89:2}
goodsTools.deleteProd = function(prodId){
delete prods[prodId];
//要让内存的对象与本地存储保持同步
this.save(prods);
}
//获取数据
goodsTools.getProds = function(id){
let prods = JSON.parse(window.localStorage.getItem('prods'))||{};
if(id){
return prods[id]; //传id返回数量
}else{
return prods;
}
}
// 本地存储prods
goodsTools.save = function(prods){
window.localStorage.setItem('prods',JSON.stringify(prods)); // [Object:object]
}
// 返回商品总数
goodsTools.getProdCount = function(){
let sum = 0;
let prods = this.getProds();
for(let id in prods){
sum += prods[id];
}
return sum;
}
export default goodsTools; // import xxx from './xxx.js'

页面操作

1-点击加入购物车 调用增加的函数 以对象的方式传入商品的id和数量

2-点击购物车 调用获取本地的数据的函数 获取数据 再用Object.keys(obj)拿到id(数组的形式)

3-拼接想要的参数 与url拼接 然后发送请求显示购物车页面

4-获取用户购物车的信息,给用户添加选中的标记(isChecked = true)添加到请求到的数据

5-通过商品id拿到本地商品的数量添加到 添加到请求到的数据

1
2
3
4
5
6
7
8
9
10
11
12
vue:
let obj = buycar.getProds();
let goodId = Object.keys(obj).join(",");
this.$ajax.get("/goods/getshopcarlist/"+goodId)
.then(res=>{
this.dataLists = res.data.message;
this.dataLists.forEach(element=> {
this.$set(element,"isChecked",true)
this.$set(element,"num",obj[element.id])
});
console.log(this.dataLists)
})

6-商品的总数量以及总价钱用监听时时刻刻监听相关的数量

1
2
3
4
5
6
7
vue----computed:{
pathname(){ // 不要使用箭头函数
return obj
}
}
{{pathname}} ====》模板中使用

vue请求数据

axios发起请求

axios

  • axios可以使用在浏览器端,也可以使用在nodejs端
  • 前端框架: vue react中使用
  • https://segmentfault.com/a/1190000008470355?utm_source=tuicool&utm_medium=referral
  • get
  • post 如果data是对象,默认头就是application/json
    • 如果data是字符串 默认头就是application/x-www-form-urlencoded
  • 在做交互的时候,application/json传输数据,你得保证,头和数据一致
  • 还要顾及服务端是否支持json数据

不是vue插件要挂载原型中

1
Vue.prototype.$ajax = Axios; //所有组件都通过this.$aixos获取对象

post

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
this.$axios.post('http://182.254.146.100:8899/api/postcomment/400',
//{content:'xxx'} 传递的是对象 转换是对象字符串做key
'content=上海9期,谦虚的登场' //需要字符串
,{
//对于本次请求的个性化设置
// headers:{
// 'content-type':'application/x-www-form-urlencoded'
// }
})
.then(res=>{
console.log(res.data);
})
.catch(err=>{
console.log(err);
})
}

get

1
2
3
4
5
6
7
this.$axios.get('http://182.254.146.100:8899/api/getlunbo')
.then(res=>{
console.log(res.data); //整个数据对象
})
.catch(err=>{
console.log(err);
})

合并请求

  • 发起一个获取省数据的请求 + 发起一个获取市数据的请求
  • 一次失败,就算失败,全部成功才算成功
  • 发起合并请求 this.$axios.all([请求1,请求2...])
  • 广播响应,在then参数内 this.$axios.spread((res1,res2)=>{ //处理响应内容})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
this.$axios.all([
this.$axios.get('http://182.254.146.100:8899/api/getnewslist'),
this.$axios.get('http://182.254.146.100:8899/api/getlunbo2')
])
.then( //需要广播
this.$axios.spread((newsListRes,lunboRes)=>{
console.log('成功');
console.log(newsListRes);
console.log(lunboRes);
})
)
.catch(err=>{
console.log('失败')
//一个出异常,就进入了
console.log(err);
})
1
2
3
4
5
//默认设置一些公共行为this.$axios.defaults是一个对象
//影响范围大、能力不强
this.$axios.defaults.headers = {
accept:'get request1'
} //覆盖

axios_interceptor拦截器

在 main.js全局中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//拦截器操作放在全局性的地方
Axios.interceptors.request.use(function(config){
//在发起请求之前做一些事
console.log(config);
config.headers.accept = 'interceptors';
//禁止
return {}; //最终告知插件要干嘛,method、url
});
//响应拦截器
Axios.interceptors.response.use(function(response){
//在响应回来以后
console.log(response);
//禁止
return response;
})

拦截器应用场景

  • loading图标 在请求发起前,显示
  • 在响应回来后,隐藏
1
2
3
4
5
6
7
8
9
10
11
12
Axios.interceptors.request.use(function(config){
MintUi.Indicator.open({ //发起请求前显示
text: '加载中...',
spinnerType: 'fading-circle'
});
return config; //最终告知插件要干嘛,method、url
});
//响应拦截器
Axios.interceptors.response.use(function(response){
MintUi.Indicator.close();//响应回来后关闭
return response;
});

OPTIONS请求(扩展)

  • 1:跨域 2:发起请求的时候由于数据是对象,插件默认加上的content-type:application/json
  • application/json 新的,且流行的
  • 浏览器会自动发起OPTIONS作为预检请求,去问一下,服务器是否搞定了content-type的相关配置
  • 避免浏览器发起预检请求
    • 如果一定要application/json,需要服务器配合
    • 一般来讲服务器都支持application/x-www-form-urlencoded

vue-rerource

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
<script>
export default {
data(){
return {
}
},
created(){
//短方法,简便 $http.get(url,options) -> $http({ method:'get'})
// this.$http.get('http://182.254.146.100:8899/api/getlunbo')
// .then(res=>{
// console.log(res);
// })
// .catch(err=>{
// console.log('出错了')
// console.log(err);
// });
//短方法,简便 $http.get(url,data,options)
this.$http.post('http://182.254.146.100:8899/api/postcomment/400',{
content:'牛逼的!'
},{
//配置
emulateJSON:true, //给请求加上application/x-www-form-urlencoded并且数据以键值对方式发送
})
.then(res=>{
console.log(res.body)
})
.catch(err=>{
console.log(err);
})
}
}
</script>

js代码转换器(bable)

babel

  • js代码转换器, ES6/ES7/react/….前端框架代码 -> ES5
  • 结合webpack来使用
  • 1:配置webpack.config.js文件中的babel-loader
  • 2:使用babel的时候,babel分为两个部分
    • babel默认只解析关键字,不处理函数
    • 预置 : ES2015 ,插件: 转换函数
  • 3:创建配置文件
    • .babelrc文件
    • 数据是一个json对象
      • { “presets”:[‘es2015’],”plugins”:[‘transform-runtime’] }
    • 以上所讲的东西都没有包含在某一个包里面,而是需要单独下载
    • babel-core才是运行的核心,babel-loader依赖于babel-core
    • babel运行的配置也需要加载,有2
  • 4:下载对应的4个包
    • babel-loader babel-core babel-preset-es2015 babel-plugin-transform-runtime
  • 资料 http://www.ruanyifeng.com/blog/2016/01/babel.html

####