• Cordova+Vue快速搭建Hybrid App


    前言

    最近项目迭代需要开发一个app,由于项目组其他系统前端技术栈都是Vue,所以自己在需求评估的时候就初步敲定了Cordova+Vue的前端架构,后来查阅了不少资料,也掉了不少坑,这里总结一下,也算是对自己这段时间摸索的回顾吧。

    项目脚手架搭建

    首先安装nodecordova,下面是我项目的版本号

    mac配置Android sdk,此处有具体教程

    vue-cli项目搭建

    安装vue-cli

    npm install -g @vue/cli
    vue init webpack vue-app
    cd vue-app
    npm i
    复制代码

    执行成功之后项目目录如下:

    之后执行npm run dev 看到浏览器如下页面,可以说明项目搭建成功了。

    cordova项目搭建

    在项目同级目录下创建cordova项目

    执行cordova create cordova-app

    项目整体目录如下:

    www目录存放编译后的前端代码,包括Html,CSS,JS

    项目整合

    下面是将vue项目编译代码的目录指向cordova的www目录,这样就可以实现项目整合了,vue项目负责页面代码编写,cordova项目负责打包和原生接口调用。

    修改之后执行npm run build 就可以看到vue-app项目的代码编译打包到cordova-app的www目录了。

    引入sass-loader

    因为vue-cli默认生成的项目是不支持sass语法的,所以需要引入sass-loader

    npm install sass-loader node-sass webpack --save-dev

    安装成功之后就可以在vue组件中愉快地编写样式了

    <style lang="scss">
        @import 'assets/style/reset.scss';
        @import 'assets/style/variable.scss';
        @import 'assets/style/common.scss';
    </style>
    复制代码

    抽离公共组件

    项目是基于平板的应用,所以需要用到一些通用UI组件,在src目录新建base文件夹,存放通用组件,此处以移动端常用的toast组件为例,加入了transition动画效果:

    <template>
        <transition name="fade">
            <div class="wrapper" v-if="show">
                <div class="container">
                    <p class="title tc">{{title}}</p>
                    <p class="content tc" v-for="msg in content" :key="msg">{{msg}}</p>
                    <p class="action tc" @click="confirm" v-if="type == 'toast'">{{action}}</p>
                    <p class="confirm tc" v-if="type == 'confirm'">
                        <span @click="cancel">{{cancelText}}</span>
                        <span @click="ok">{{okText}}</span>
                    </p>
                </div>
            </div>
        </transition>
    </template>
    
    <script>
        export default {
            // 弹窗组件
            name: 'Toast',
            props: {
                type: {
                    type: String,
                    default: 'toast'
                },
                show: {
                    type: Boolean,
                    default: false
                },
                title: {
                    type: String,
                    default: ''
                },
                content: {
                    type: Array,
                    default: null
                },
                action: {
                    type: String,
                    default: '确定'
                },
                cancelText: {
                    type: String,
                    default: '取消'
                },
                okText: {
                    type: String,
                    default: '确定'
                }
            },
            methods: {
                confirm() {
                    this.$emit('confirm')
                },
                cancel() {
                    this.$emit('cancel')
                },
                ok() {
                    this.$emit('ok')
                }
            }
        }
    </script>
    
    <style scoped lang="scss">
        @import '../assets/style/variable.scss';
        .wrapper {
            z-index: 999;
            background-color: $black-color3;
            position: fixed;
            top: 0;
            left: 0;
             100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            .container {
                 400px;
                border-radius: 4px;
                background-color: #eee;
                .title {
                    color: #333;
                    font-size: 28px;
                    line-height: 28px;
                    margin: 40px 0 20px 0;
                }
                .content {
                    color: #666;
                    font-size: 24px;
                    line-height: 31px;
                    font-weight: 200;
                    padding: 0 32px;
                }
                .action, .confirm {
                    border-top: 2px solid #ddd;
                    height: 80px;
                    line-height: 80px;
                    font-size: 28px;
                    color: #007AFF;
                    margin-top: 40px;
                }
                .confirm {
                    display: flex;
                    span {
                        flex-grow: 1;
                        &:first-child {
                            border-right: 2px solid #ddd;
                            color: #333;
                        }
                    }
                }
            }
        }
    </style>
    复制代码

    调用Cordova插件

    之所以要开发成app,自然是需要调用设备原生api,cordova有相当多的插件供开发者使用,只需要安装添加到cordova-app项目即可调用。

    类似扫码功能cordova plugin add phonegap-plugin-barcodescanner

    vue-app当中调用时也很简单:

    if (window.cordova && window.cordova.plugins.barcodeScanner) {
        window.cordova.plugins.barcodeScanner.scan((result) => {
            if (result && result.text) {
                alert(result.text)
            }
        }, (err) => {
            console.log(err)
        }, {
            prompt: '', // 提示文字
            resultDisplayDuration: 0// 扫描成功文字停留时间
        })
    }
    复制代码

    不过,当你打包出来会发现window.cordovaundefined,其实你还漏了一步,cordova打包之后调用插件需要手动引入cordova.js,而我们的vue代码并没有这一步操作,所以我们需要在main.js里面加入:

    // 增加cordova文件
    if (window.location.protocol === 'file:') {
        let cordovaScript = document.createElement('script')
        cordovaScript.setAttribute('type', 'text/javascript')
        cordovaScript.setAttribute('src', 'cordova.js')
        document.body.appendChild(cordovaScript)
    }
    复制代码

    这样打包就大功告成了。

    引入Vuex

    单页应用在共享数据上存在一定的麻烦,所以此时Vuex就登场了。

    在src增加以下目录文件:

    此处我们实现一个wifi连接状态以及名称的管理。具体看以下代码:

    getter.js

    export const wifi = state => state.wifi
    复制代码

    index.js

    import Vue from 'vue'
    import Vuex from 'vuex'
    import * as getters from './getters'
    import state from './state'
    import mutations from './mutations'
    import createLogger from 'vuex/dist/logger'
    
    Vue.use(Vuex)
    
    const debug = process.env.NODE_ENV !== 'production'
    
    export default new Vuex.Store({
        getters,
        state,
        mutations,
        strict: debug,
        plugins: debug ? [createLogger()] : []
    })
    复制代码

    mutation-types.js

    export const SET_WIFI_STATUS = 'SET_WIFI_STATUS'
    export const SET_WIFI_NAME = 'SET_WIFI_NAME'
    复制代码

    mutations.js

    import * as types from './mutation-types'
    
    const matutaions = {
        [types.SET_WIFI_STATUS](state, status) {
            state.wifi.status = status
        },
        [types.SET_WIFI_NAME](state, name) {
            state.wifi.name = name
        }
    }
    
    export default matutaions
    复制代码

    state.js

    const state = {
        wifi: {
            status: false,
            name: ''
        }
    }
    
    export default state
    复制代码

    结语

    代码创造世界,世界属于三体。后会有期。

  • 相关阅读:
    Ajax 异步请求返回集合遍历问题
    JS 类数组,字符串,转换成数组的方法
    laravel、TP、YII三个框架的优缺点对比
    纵深防御
    渗透测试小结
    常见的设计模式
    CDN简介
    WAF小介
    分布式事务及其常见的解决方案
    redis主从复制
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/10734350.html
Copyright © 2020-2023  润新知