项目的大致需求就是做一个App,里面集成各种功能供用户使用,其中涉及到很多Vue的使用方法,单独总结太麻烦,所以通过这几篇笔记来梳理一下。原型图如下:

路由配置

主界面会用到一些原生App方法,比如验证用户身份等,故由原生App完成,进去的每个模块则全部都是HTML页面(有一种后端工作好轻松的感觉 ̄へ ̄)。由于传统的HTML页面开发起来效率太低,所以我选择了Vue来实现。每一个功能对应一个路由,比如电脑报修对应/repair,repair这个路由下的子页面都放进子路由里。

├─repair

│ apply.vue

│ index.vue

│ payment.vue

│ repairList.vue

└─teambuilding

apply.vue

index.vue

const router = newRouter({

mode:'history',

routes: [

path:'/repair',

component: repair,

children: [

{path:'apply', component: repairApply}, //电脑报修申请

{

path:':id',//报修单详情

component: repairDetail,

children: [

{name:'evaluate', path: 'evaluate', component: repairEvaluate}, //服务评价

{name: 'evaluatePay', path: 'pay', component: pay} //支付

]

}

]

]

})

为了减小打包时的体积,在加载组件的时候采用了以下形式:

const repair = resolve => import('views/repair/index').then(module =>resolve(module))

const repairApply= resolve => import('views/repair/apply').then(module =>resolve(module))

const repairDetail= resolve => import('views/repair/detail').then(module => resolve(module))

这是按照官方文档提供的路由懒加载技术写的,这样就能实现当路由被访问的时候才加载对应组件。以上是项目中关于路由的一些用法。

注册全局组件

接下来是全局组件的用法,比如头部,等待加载,弹出层之类的组件,几乎每个页面都有,全局注册能省去不少事。

import header from 'components/header/header'import loading from'components/loading/loading'Vue.component('v-header', header)

Vue.component('loading', loading)

之后在每个页面中敲入就能直接使用了,不用每次都去import。

处理返回键

还有一个比较常见的问题,由于Vue做出来的页面是一个SPA,在Android机中如果按下了物理返回键,整个应用都会退出,解决方法是重写物理返回键,这样就能按路由一级一级地返回了。因为主界面是由原生实现的,所以Vue只能返回到对应模块的首页,比如从 /repair/apply -> /repair -> null ,想要回到原生主界面,需要后端向前端注入一段脚本,在模块首页的后退按钮被点击时,执行一段方法告知Android调用自身的逻辑,然后Android关闭当前页面并回到主界面,例如:

//在main.js中加入该方法

window.AndroidMethod = function(msg) {if (window.android !== null && typeof(window.android) !== "undefined") {

window.android.callAndroid(msg);

}

}

在头部组件header.vue中,可以使用如下方式:

methods:{

goback() {

window.history.length> 1 ? this.$router.go(-1) : this.$router.push('/')

},

backToHomePage() {

AndroidMethod('backToHomePage')

}

}

这样可以将模块首页的返回和子路由的返回区分开来。

如果使用其他的打包工具,比如apiCloud或者HBuilder,它们都有各自的阻止物理返回按键的方法:

//apiCloud

api.addEventListener({

name:'keyback'},function(ret, err){

});

});//HBuilder

//https://blog.csdn.net/qq_25252769/article/details/76913083

document.addEventListener('plusready', function() {var webview =plus.webview.currentWebview();

plus.key.addEventListener('backbutton', function() {

webview.canBack(function(e) {if(e.canBack) {

webview.back();

}else{

webview.close();

}

})

});

});

同样的,把这些代码放在main.js中即可,打包后在真机里运行时会执行这些方法,普通环境是不存在这些变量的。

接收后端返回的数据

有时候,我们希望在Vue初始化时就能设置一些从服务器获取的常量,比如userID等,之后在各个组件中就能很方便地访问。设置全局变量很简单,直接挂载在Vue.prototype后面即可:

axios.get('http://localhost/index.php').then(res =>{

Vue.prototype.uid=res.data.uid

Vue.prototype.appid=res.data.appidnewVue({

el:'#app',

router,

store,

render: h=>h(App)

})

})

在组件中使用this.uid、this.appid就能访问到从服务器获取的常量了。如果是普通的js文件(比如api,utils等等),可以通过

import Vue from 'vue'Vue.prototype.uid

来访问。我们可能还希望这些数据在初始化时也能同时保存到Vuex中,先来看一下最初的Store/index.js文件:

import Vue from 'vue'import Vuex from'vuex'import* as actions from './actions'import* as getters from './getters'import state from'./state'import mutations from'./mutations'exportdefault newVuex.Store({

actions,

getters,

state,

mutations

})

但这样就没有往Vuex中存入数据的机会,这时就需要对Store文件夹中的index.js做一些小的封装,使其返回一个方法:

functionbuidler(data) {return newVuex.Store({

actions,

getters,

state: data,

mutations

})

}

exportdefault buidler

然后修改main.js中调用Vuex的方式,最初的代码如下:

import store from './store'

newVue({

el:'#app',

router,

store,

render: h=>h(App)

})

修改后的代码如下:

import store from './store'axios.get('http://localhost/index.php').then(res =>{

Vue.prototype.uid=res.data.uid

Vue.prototype.appid=res.data.appidnewVue({

el:'#app',

router,

store:store(res.data),

render: h=>h(App)

})

})

在组件的created方法中用MapGetters输出一下uid和appid,发现值可以被打印出来,说明这种实现方式是可以采用的。

更新:在后续的测试中,发现一些机型,特别是华为机(实测iOS没有此问题),对这种延后初始化Vue的方式兼容不好,表现在所有路由的切换动画全部失效,页面后退时会重新渲染页面(执行组件created方法中的内容),设置keep-alive也没有效果。不过水平有限,实在弄不懂为什么会这样。为了兼容,就不能采用上面的方式了。最后使用了在请求头中携带cookie的方式,具体为webview加载vue页面时,在requestURL中注入cookie,在cookie中设置需要传递的值,下面是用PHP模拟的一个小例子,PHP加载HTML页,并注入cookie,在HTML加载时取到cookie。

PHP:

HTML:

这样就能在main.js里同步拿到userID,Vue也不用延迟初始化了,Android机的表现效果和iOS一致。拿到userID后,可以保存到配置文件config中,在每个组件中访问config.uid就能拿到。

better-scroll

App中最常见的组件就是滚动数据列表,由此又很容易联想到better-scroll这个插件。better-scroll虽然好用,但如果使用不当还是会造成不小的麻烦,一些错误甚至无从排查。这里主要记录一下下拉刷新和上拉加载更多的实现。容器结构如下:

最外层的div限制滚动内容的位置,srcoll是官网提供的已经封装好的组件,里面正常置入ul>li形式的列表就行了,ul和li都不需要特殊的样式。由于官网提供的例子中整合了许多文件,查阅起来不是很方便,于是将其剥离出来,写了一个只有上拉加载和下拉刷新的Demo,方便以后使用。使用scroll时要慎用v-show指令,比如我希望使用下面的代码来控制没有数据时容器的显示与隐藏,由于数据是异步加载,刚开始时容器不显示直到数据加载好为止。

data() {return{

dataList: []

}

}

但这样会造成scroll组件内部高度计算错误(offsetHeight被计算成0,这是由于容器处于display:none状态),如果此时列表的数据没有达到滚动要求,上拉和下拉的提示文字会显示在列表下方,网速慢时也无法使用上拉下拉功能。解决方法是使用v-if指令,这样容器的min-height高度就能被正确计算了。

图片上传

另外一个功能是图片上传,这个功能并非由前端完成,而是和上面一样,通过后台返回的一段函数体拿到上传图片的路径并展示出来。

相册和拍摄都由后台调起,前端只需要进行简单的传值就行了:

AndroidMethod('photo')

AndroidMethod('video')

代码是和后端约定好的,所以不需要操心。真正需要关注的是从后台返回的图片上传路径,拿到这个路径后要在前台展示,并且保存时要带上一个或多个路径组成的字符串。

这个方法同样是和后台约定好的方法:

window.getUpload = function(path) {//这里要将path保存起来拿到组件里使用

}

这里就需要使用全局变量将path保存起来,假定这个全局变量叫做uploadImgUrl,初始化时是一个空数组,只有当用户从相册里选择图片上传后才将拿到的路径赋给这个全局变量。Vue组件中要监听这个全局变量的变化,就不能使用Vue.prototype.uploadImgUrl这种方式了,因为Vue要监听某个变量的变化,必须将这个变量放在data中,改进一下之前的代码:

import store from './store'axios.get('http://localhost/index.php').then(res =>{

Vue.prototype.uid=res.data.uid

Vue.prototype.appid=res.data.appid

let vm= newVue({

el:'#app',

router,

data() {return{

uploadImgUrl: []

}

},

store:store(res.data),

render: h=>h(App)

})

window.getUpload= function(path) {

vm.uploadImgUrl=path

}

})

上面将变量存放在根组件的data中,在其它组件内就可以通过以下形式访问到

this.$root.$data.uploadImgUrl

虽然拿到了路径,但问题还没有结束,因为这个值是动态变化的,需要使用计算属性来监测它的变化,下面是核心代码:

data() {return{

loadedImgs:[]//保存已上传的图片

}

},

methods: {

deleteImg(index) {for (let i = 0; i < this.loadedImgs.length; i++) {if (index ===i) {this.loadedImgs.splice(i, 1)break}

}

},

computed: {

imgsList() {this.loadedImgs = this.loadedImgs.concat(this.$root.$data.uploadImgUrl)this.$root.$data.uploadImgUrl =[]  //每次合并完重置一下return this.loadedImgs

}

},

created() {this.$root.$data.uploadImgUrl =[]  //组件创建时先重置一下之前的值

}

}

}

通过computed计算属性,无论是添加图片或者删除图片都能正确展示了。

真机调试

在真机上调试非常不方便,很多调试信息看不到,不过vconsole这个插件解决了这个问题,安装方法非常简单,在依赖里(开发环境或正式环境均可)安装vconsole,然后在main.js中

import Vconsole from 'vconsole'

new Vconsole()

打开页面就能看到右下角多出了一个vConsole的图标,项目中所有console.log的信息都会输出到这个vConsole面板里。

结束

知识点比较繁杂,所以文章有点乱,暂时先总结到这,后续还有很多坑待填。

vue做混合式app_Vue+原生App混合开发手记#1相关推荐

  1. vue做混合式app_Vue Cordova教程-Vue+Cordova打造跨平台可安装的混合APP视频教程(大地)...

    Vue+Cordova打造跨平台可安装的混合APP视频教程 必看说明: 目前购买此教程送Html5+Cordova+Ionic智能电视(TV)应用开发教程视频教程: 购买过Ionic的同学可以直接在( ...

  2. 教你如何使用Flutter和原生App混合开发

    点击上方 "程序员小乐"关注, 星标或置顶一起成长 每天凌晨00点00分, 第一时间与你相约 每日英文 Things in this world are temporary. If ...

  3. Flutter和原生App混合开发

    可以查看官方文档 https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps 混合开发有两种集成方式 Flutter源码集 ...

  4. zx-editor 移动端(HTML5)富文本编辑器,可与原生App混合(hybrid)开发

    zxEditor 移动端HTML文档(富文本)编辑器,支持图文混排.引用.大标题.无序列表,字体颜色.加粗.斜体. 可用于独立web项目开发,也可以用于与原生App混合(hybrid)开发. 源码地址 ...

  5. App混合开发-前端小白理解

    什么是混合app 混合开发的App(Hybrid App)就是嵌一个轻量级的浏览器,一部分原生的功能改为Html5来开发,这部分功能不仅能够在不容升级的情况下动态更新,而且可以在Android或iOS ...

  6. 谈谈Android App混合开发

    推酷 文章 站点 主题 公开课 活动 客户端 荐 周刊 登录 谈谈Android App混合开发 时间 2015-08-25 20:13:43bxbxbai 原文  http://bxbxbai.gi ...

  7. 六十五、完成Vue项目去哪儿网App首页开发(来源:慕课网)

    2020/10/21. 周三.今天又是奋斗的一天. @Author:Runsen @Date:2020/10/21 写在前面:我是「Runsen」,热爱技术.热爱开源.热爱编程.技术是开源的.知识是共 ...

  8. 4个月原生weex混合开发终结()

    原因 由于一些h5人员方面的原因,新的非主流程需求将全部由app人员开发.然后app的人员已经由15人缩减成ios和android各两个了.为了应对3个产品各自负责的需求,我们调研了weex和rn. ...

  9. html5触摸界面设计与开发_原生APP的开发步骤主要分为哪些?

    移动APP的发展也来也好,APP的开发也是越来广泛,同时APP也是有这多种的开发方式.济南网站建设的小编在之前的文章"一起企业APP开发前首先要确定哪些?"中就有提到过APP开发模 ...

最新文章

  1. .Net平台Winform两个ComboBox控件绑定同一个数据源
  2. 修改Linux终端命令行字体颜色(对比明显,超炫酷)
  3. openssl简介-指令asn1parse
  4. react中webpack.config.js配置lessless-loader less
  5. python中匿名函数的作用_什么是Python中的匿名函数
  6. 从方法返回Java 8的可选项时的注意事项
  7. php websocket应用实例,php使用websocket示例详解
  8. 让人想骂街的 Python 炫技操作:条件语句的七种写法
  9. Exchange Server 2013系列五:虚拟化部署
  10. 监控服务器Nagios之一 概述及安装
  11. spring配置文件各个属性详解
  12. 这月绩效差点没了!搞了一个“新人拼团”活动遇到黑产,搭进去了8台服务器......
  13. 在9i的数据库中排除某些表做owner级导出
  14. 拓端tecdat|使用OpenCV在Python中进行图像处理
  15. I2S音频接口的理解
  16. 世纪互联评测至强5500 总结云平台经验
  17. 每秒1.28万亿行,最快的分布式关系数据库MemSQL又破记录了!
  18. 头文件到底是干啥用的
  19. Java调用MaxMind GeoIP库查询IP地理信息
  20. Google产品经理面试题:村子里有100对夫妻,其中每个丈夫都瞒着自己的妻子偷情......

热门文章

  1. Matplotlib从文件绘图时Y轴坐标不正确
  2. 47.leetcode36_valid_suduko
  3. 进阶攻略|前端最全的框架总结
  4. Java微信公众平台获取签名
  5. ufldl学习笔记与编程作业:Multi-Layer Neural Network(多层神经网络+识别手写体编程)...
  6. linux —— shell 编程(文本处理)
  7. Eclipse自动补全功能轻松设置 || 不需要修改编辑任何文件
  8. 基于boost asio实现的支持ssl的通用socket框架
  9. 华为开始对嵌入式开发者下手了!
  10. 一个小码农对嵌入式的理解