uni-app 0基础学习

1.uni-app是什么

官网链接:https://uniapp.dcloud.io/component/README
微信小程序官网:https://developers.weixin.qq.com/miniprogram/dev/component/

  • 前端跨端框架
    使用vue.js开发所有前端应用的框架
  • 跨端解决方案
    只需开发一套代码,即可发布多平台

2.uni-app的主要特征

截屏2020-02-17上午11.01.04.png

3.uni-app解决了什么问题

  • 多平台统一的开发(微信,百度,支付宝,字节跳动,QQ小程序,)
  • 过去的跨端框架性能不够优秀
  • 生态不丰富

4.创建uni-app工程

  • 最好使用HBuilderX开发工具
    一般为了稳定使用正式版,标准版只是简单的一个编辑器,不能进行app开发,因为没有预装app开发的环境,所以可以下载app开发版,它已经集成了相关的插件
    WechatIMG19.jpeg
  • 创建项目
    方法一: 通过 HBuilderX 可视化界面
    1.在点击工具栏里的文件 -> 新建 -> 项目
    2.选择uni-app,输入工程名,如:hello-uniapp,点击创建,即可成功创建 uni-app。点击模板里的 Hello uni-app 即可体验官方示例。
    WechatIMG26.png

    方法二:通过vue-cli命令行
// 1.使用正式版(对应HBuilderX最新正式版)
vue create -p dcloudio/uni-preset-vue my-project
// 2.使用alpha版(对应HBuilderX最新alpha版)
vue create -p dcloudio/uni-preset-vue#alpha my-alpha-project
// 接下来选择模版

5.运行平台

  • H5
  • APP
  • 小程序(微信,支付宝,百度,头条,QQ)

6.目录结构说明

WechatIMG36.jpeg

WechatIMG34.jpeg

7.页面配置(pages.json)

pages.json 文件用来对 uni-app 进行全局配置,决定页面文件的路径、窗口样式、原生的导航栏、底部的原生tabbar 等。(所有的页面必须要在pages.json里面注册,否则页面将不会展示)

它类似微信小程序中app.json的页面管理部分。注意定位权限申请等原属于app.json的内容,在uni-app中是在manifest中配置。

  • pages的配置说明(所有的页面必须要在pages里面注册,否则页面将不会展示)


    WechatIMG49.png

    18619776-70a4345b0a58e47d.png
  • globalStyle
    用于设置应用的状态栏、导航条、标题、窗口背景色等。会被pages里style的样式覆盖


    截屏2020-02-17下午1.05.42.png
  • tabBar
    如果应用是一个多 tab 应用,可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页。
"tabBar": {
    "color": "#7A7E83",//颜色
    "selectedColor": "#3cc51f",//选中后的颜色
    "borderStyle": "black",
    "backgroundColor": "#ffffff",//背景色
    "list": [{
        "pagePath": "pages/component/index",//组件路径
        "iconPath": "static/image/icon_component.png",//未选中时的图标
        "selectedIconPath": "static/image/icon_component_HL.png",//选中时的图标
        "text": "组件"//中文文案
    }, {
        "pagePath": "pages/API/index",
        "iconPath": "static/image/icon_API.png",
        "selectedIconPath": "static/image/icon_API_HL.png",
        "text": "接口"
    }]
}
/**
注意:
1.list下最多配置5项,最少配置2项;
2.tabbar显示一次就会保存到内存中,以后每次打开不会重新请求资源,如果需要重新加载页面,需要在onshow的生命周期中做逻辑运算,达到刷新页面的操作
3.有些属性在某些平台是不支持的
**/

8.基础组件

<template>
<!-- 
1.vue文件:自定义的文件类型,类html语法,描述的一个vue
2.三部分组成:
    - template 视图层 组件
    - script 逻辑层
    - style 样式层
3.常用的基础组件
    -view  ->  div  容器组件
    -text  ->  span  文字组件
    -image  ->  img  图片组件
 -->
    <view class="content">
        <image class="logo" src="/static/logo.png"></image>
        <view class="text-area">
            <text class="title">{{title}}</text>
        </view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                title: 'Hello'
            }
        },
        onLoad() {

        },
        methods: {

        }
    }
</script>

<style>
    .content {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
    }   
</style>

9.生命周期

  • 应用生命周期
    应用生命周期仅可在App.vue中监听,在其它页面监听无效。
<script>
    // 只能在App.vue里监听应用的生命周期
    export default {
        //当uni-app 初始化完成时触发(全局只触发一次)
        onLaunch() {},
        //当 uni-app 启动,或从后台进入前台显示
        onShow() {},
        //当 uni-app 从前台进入后台
        onHide() {},
      //当 uni-app 报错时触发
        onError() {}
    }
</script>
  • 页面生命周期
<!-- 
两个页面,A页面 B页面
A  进入  B
1.A onHide
2.B onLoad
3.B onShow
4.B onReady

B  进入  A
1.B onUnload
2.A onShow
-->
<script>
   export default {
        //页面加载
        onLoad(e) {
          //接收上个页面传来的参数(比如从路由传过来的{id:566})
          //请求后台接口
          //渲染前的操作
        },
        //页面显示
        onShow() {},
        //页面渲染完成
        onReady() { //获取节点信息},
        //页面隐藏
        onHide() {},
        //页面卸载
        onUnload() {}
  }
</script>
WechatIMG155.jpeg
  • 组件生命周期
    uni-app 组件支持的生命周期,与vue标准组件的生命周期相同。这里没有页面级的onLoad等生命周期:

10.路由

uni-app 有两种页面路由跳转方式:使用navigator组件跳转、调用API跳转。

<template>
    <navigator url="../../App">组件跳转</navigator>
    <button type="primary" @click="open">navigateTo跳转</button>  
</template>

<script>
    export default {
        data() {
            return {
                title: 'Hello'
            }
        },
        methods: {
            //uni.navigateTo保留当前页面,跳转到应用内的某个页面,使用uni.navigateBack可以返回到原页面。
            open(){
                uni.navigateTo({
                    url:'../../App'
                })
            },
            //uni.redirectTo关闭当前页面,跳转到应用内的某个页面。
            //uni.reLaunch关闭所有页面,打开到应用内的某个页面。   
            //uni.switchTab跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。    
            //uni.navigateBack关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。 
        }
    }
</script>

10.语法(和vue一样)

<template>
    <view>
        <!-- 动态绑定数据 -->
        <text class="title">{{title}}</text>

        <!-- 动态绑定属性 -->
        <image class="logo" :src="src"></image>
    
        <!-- 动态class -->
        <view :class="content"></view>
        <view :class="[content,background]">会把数组里的都渲染</view>
        <view :class="{content:flag}">flag是一个布尔值,如果是true样式就会渲染,否则样式就不被渲染</view>

        <!-- 动态style 还有数组和对象的绑定方式没有展示-->
        <view style="border: 1px solid red">111</view>
        <view :style="{background: 'red'}">222</view>
        <view :style="{background: background1}">333</view>
        <!-- 对象方式-->
        <view :style="{backgroundImage:`url(${imgUrl})`}">222</view>
        <view :style="{ paddingTop: paddingTopNum + 'px' }">333</view>


        <!-- 条件渲染 -->
        <view v-if="show">条件渲染show是布尔值</view>
        <view v-else></view>

        <!-- 列表渲染 必须加key属性-->
        <view v-for="(item,i) in arr" :key="i">{{item}}</view>

        <!-- 事件绑定 绑定的方法需要写在methods里-->
        <view @click="onClick('uni')">点击</view>
        <input type="text" value="" @input='change'/>
    </view> 
</template>

<script>
    export default {
        data() {
            return {
                title: 'Hello',
                src:'/static/logo.png',
                // class
                content:'content',
                background:'background',
                flag:true,

                // style
                background1:'green',
                imgUrl:'/static/image/logo1.png',
                paddingTopNum:10,

                show:true,
                arr:[111,222,333,444,555]
            }
        },
        methods: {
            onClick(e){
                console.log("参数",e)
            },
            change(e){
                //方法和属性都是用this调用
                this.onClick()
                this.title="改变title"
                console.log('事件对象',e)
            }
            
        }
    }
</script>

<style>
    .content {
        border: 1px solid yellow;
    }
    .background{
        background-color: green;
    }
</style>
  • 添加样式
//style样式设置
//对象方式
:style="{ backgroundImage:`url(${topBgImg})` }"
:style="{ left:`${iconDistance}rpx` }"
:style="{ paddingTop: paddingTopNum + 'px' }"
//对象数组方式
:style="[{ color: activeColor, fontSize: fontSize + 'px' }]"
//calc
:style="{height:'calc(100vh - ' + pageTopHeight +'px - 140rpx)'}"

//class样式设置
//对象方式
:class="{ active: isActive, 'text-danger': hasError }" 
:class="[activeClass, errorClass]"

//三元运算方式
:class="[isActive ? activeClass : ' ', errorClass]"
//数组加三元运算方式
:class="[items.isShow?'':'noneActive',subIndex[index] == indexs?'value-item-active':'value-item']"

//数组加对象方式
:class="[{ active: isActive }, errorClass]"

11.布局与样式

  • 尺寸单位

(1)px 即屏幕像素
(2)rpx 即响应式px,一种根据屏幕宽度自适应的动态单位。以750宽的屏幕为基准,750rpx恰好为屏幕宽度。屏幕变宽,rpx 实际显示效果会等比放大。
uni-app 规定屏幕基准宽度 750rpx。
(3)开发者可以通过设计稿基准宽度计算页面元素 rpx 值,设计稿 1px 与框架样式 1rpx 转换公式如下:
设计稿 1px / 设计稿基准宽度 = 框架样式 1rpx / 750rpx
换言之,页面元素宽度在 uni-app 中的宽度计算公式:
750 * 元素在设计稿中的宽度 / 设计稿基准宽度

举例说明:
(1)若设计稿宽度为 750px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 uni-app 里面的宽度应该设为:750 * 100 / 750,结果为:100rpx
(2)若设计稿宽度为 640px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 uni-app 里面的宽度应该设为:750 * 100 / 640,结果为:117rpx
(3)若设计稿宽度为 375px,元素 B 在设计稿上的宽度为 200px,那么元素 B 在 uni-app 里面的宽度应该设为:750 * 200 / 375,结果为:400rpx。
HBuilderX有自带的可以配置px和rpx的转换,不用每次手动计算

WechatIMG243.png

  • 样式导入
    uni-app 内置了常用的样式变量,采用 scss 预处理方式,文件名为 uni.scss,在代码中无需 import 这个文件即可使用这些样式变量。
<!-- App.vue -->
<script>
    export default {}
</script>

<style>
    /*1.每个页面公共css,可以直接在其他页面使用 */
      .border{
        border: 1px solid red;
    }
    /*2.不想在App.vue里写的话可以在外面新建一个base.css ,然后在这里引进来,也可以在某个组件里引用*/
    @import './common/base.css'
</style>

12.基础API(自行参考文档)

12.自定义组件(和vue一样)

//pages/index/index.vue
<template>
    <view>
        <list :name="11" @onClick='onClick'></list>
        <list :name="22"></list>
    </view> 
</template>
<script>
    /**1.在项目根目录创建components目录
    2.创建组件
    3.引入组件
    4.注册组件
    5.传参
    6.事件通讯
    **/
    import list from '@/components/list.vue'
    export default {
        components:{list},
        methods: {
            onClick(val){
                console.log(val)
            }
        }
    }
</script>
//components/list.vue
<template>
    <view class="list" @click="onClick">{{name}}</view>
</template>

<script>
    export default {
        props:{
            name:{
                type:Number,
                default:null
            }
        },
        methods: {
            onClick(){
                this.$emit('onClick',this.name)
            }
        }
    }
</script>
<style>
.list{
    border: 1px solid red;
    width: 100px;
    height: 100px;
}
</style>

13.自定义导航栏

image.png
image.png
  • 最近需要获取小程序页面中 胶囊的 frame (y,x,w,h)等数据,可以通过wx/uni提供的能力(如果用的是原生,则将以下代码中的uni换为wx即可)
//胶囊的位置信息
var data = uni.getMenuButtonBoundingClientRect()
    console.log('胶囊宽度:',data.width)
    console.log('胶囊高度:',data.height)
    console.log('胶囊上边界坐标:',data.top)
    console.log('胶囊右边界坐标:',data.right)
    console.log('胶囊下边界坐标:',data.bottom)
    console.log('胶囊左边界坐标:',data.left)
//获取状态栏高度
uni.getSystemInfo({
    success(res) {
        console.log("状态栏的高度:" + res.statusBarHeight)
    }
})

//2.计算头部高度
//在app.vue中
onLaunch: function() {
    uni.getSystemInfo({
      success: (res) => {
        const statusBarHeight = res.statusBarHeight //状态栏高度
        const menuButton = uni.getMenuButtonBoundingClientRect() //胶囊的信息
        //(menuButton.top - res.statusBarHeight) * 2//导航栏上下内边距
        const navHeight = menuButton.height + (menuButton.top - res.statusBarHeight) * 2 // 导航栏高度
        const headerHeight = navHeight + statusBarHeight // 总高度(状态栏+导航栏)
        // 存储到Vue里
        Vue.prototype.navData = { statusBarHeight, navHeight, headerHeight }
        // 存储到本地存储
        uni.setStorage({
          key: 'navData',
          data: { statusBarHeight, navHeight, headerHeight }
        })
      }
    })
  }
  • 自定义导航栏组件
    app.vue中获取个高度
<script>
    export default {
        onLaunch() {
            // uni.getSystemInfo 获取设备信息 
            // uni.getMenuButtonBoundingClientRect 获取胶囊数据
            // uni.setStorage 异步本地存储
            uni.getSystemInfo({
                success: (res) => {
                    const menuButton = uni.getMenuButtonBoundingClientRect() // 胶囊
                    const navBarPadding = (menuButton.top - res.statusBarHeight) * 2
                    const statusBarHeight = res.statusBarHeight //状态栏高度
                    const navHeight = menuButton.height + navBarPadding // nav高度
                    const headerHeight = navHeight + statusBarHeight // 总高度
                    uni.setStorage({
                        key: 'navData',
                        data: {statusBarHeight,navHeight,headerHeight}
                    })
                    console.log(statusBarHeight, navHeight, headerHeight, ) // 20 40 60 iphone6/7/8
                }
            })
        },
        onShow: function() {
            console.log('App Show')
        },
        onHide: function() {
            console.log('App Hide')
        }
    }
</script>

<style>
    /*每个页面公共css */
</style>

封装导航组件

<template>
    <view>
        <view class="navBar">
            <view class="navBar_statusBar" :style="{height: statusBarHeight + 'px'}"></view>

            <view class="navBar_head" :style="{height: navHeight + 'px',lineHeight: navHeight + 'px'}">
                <view class="navBar_callback">
                    <image v-if="callback" @click="callBack" src="../static/vertical/callBack.png"></image>
                </view>
                <p class="navBar_content">{{content}}</p>
            </view>
        </view>

        <view class="navBox" :style="{height: headerHeight + 'px'}"></view>
    </view>

</template>

<script>
    export default {
        props: {
            callback: {
                type: Boolean,
                default: true
            },
            content: {
                type: String,
                default: '首页'
            }
        },
        data() {
            return {
                statusBarHeight: '',
                navHeight: '',
                headerHeight: '',
            };
        },

        created() {
            let _this = this
            uni.getStorage({
                key: 'navData',
                success({ data }) {
                    _this.statusBarHeight = data.statusBarHeight
                    _this.navHeight = data.navHeight
                    _this.headerHeight = data.headerHeight
                }
            });
        },
        methods: {
            callBack() {
                uni.navigateBack({

                })
            }
        }
    }
</script>

<style lang="scss">
    .navBar {
        position: fixed;
        top: 0;
        left: 0;
        z-index: 999;
        background-color: $green;
        width: 750rpx;

        .navBar_head {
            padding: 0 56rpx;
            display: flex;
            align-items: center;
            height: 53rpx;
            font-size: 36rpx;
            font-family: PingFang SC;
            font-weight: bold;
            color: #FFFFFF;
            line-height: 53rpx;
            text-align: center;

            .navBar_callback {
                position: absolute;
                left: 56rx;

                image {
                    width: 30rpx;
                    height: 30rpx;
                }
            }

            .navBar_content {
                width: 100%;
            }
        }
    }

    .navBox {
        width: 750rpx;
    }
</style>
  • 小程序右上角的胶囊颜色怎么修改,pakeage.json
{
  "navigationBarBackgroundColor": "#f83e06",
  "navigationBarTitleText": "服务中心",
  "navigationBarTextStyle": "white"
}

修改效果:
"navigationBarTextStyle":"white"


image.png

"navigationBarTextStyle":"black"


image.png

14.封装全局登录检查函数

WechatIMG218.jpeg
WechatIMG219.jpeg
WechatIMG220.jpeg
WechatIMG221.jpeg

15.定位

想获取用户的位置,首先需要获取权限,该权限需要在manifest.json里设置

"permission": {
    "scope.userLocation": {
        "desc": "你的位置信息将用于小程序位置接口的效果展示"
    }
}

image.png

之后参考官网:https://uniapp.dcloud.io/api/location/location

16.修改uniapp组件样式

自己尝试了很多种方式,最后经过查阅资料发现,style标签上加scoped,同时使用 deep 穿透 可以成功修改:

<style scoped>
/deep/ .uni-combox__input {
    font-size: 14px;
}
</style>

17.url参数传递对象

开发小程序和uni-app时,遇到需要在navigaor组件中传递对象参数到下一个页面的需求,传递对象时如果不JSON.stringify的话,接收到的对象会被转化成[object,object]形式。但是使用字符串化往往还会带来另一个问题,那就是超出规定的长度。那么怎么解决呢?方案如下,两步走:

  • 1.使用encodeURIComponent以及JSON.stringify()方法对对象进行字符串化和编码,这样可以控制url参数的长度,参考示例代码(uni-app书写方式,微信小程序自己改。)
    <navigator :url="'/pages/base/baseEdit/baseEdit?item='+ encodeURIComponent(JSON.stringify(item))"></navigator>
    
  • 2.接受信息的页面使用JSON.parse()以及decodeURIComponent()接收和解码参数。
    onLoad(option){
      const item = JSON.parse(decodeURIComponent(option.item));
    }
    

上述两步即可解决url传递的对象的被编码和长度超长问题了
参考:https://blog.csdn.net/qq_16371909/java/article/details/91361734

18.获取从哪跳转过来的页面地址

 var pages = getCurrentPages(); // 当前页面
 var beforePage = pages[pages.length - 2]; // 前一个页面
 var route=pages[pages.length - 2].route;//前一个页面的路由

 wx.navigateBack({
     success: function() {
         beforePage.onLoad(); // 执行前一个页面的onLoad方法
     }
 });

19.placeholder样式修改

<input type="text" style="font-size: 34upx;" placeholder-style="font-size:16px;" placeholder="患者姓名" confirm-type="search"></input>

19.uni如何执行input中回车键的监听

按键修饰符:uni-app运行在手机端,没有键盘事件,所以不支持按键修饰符。
那如果有一个需求,希望在input中输入之后,按回车键执行一个查询,应该如何实现?

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

推荐阅读更多精彩内容

  • 上一篇我们讲了uni-app的各种优缺点,接下来我们要讲一下uni-app的开发流程和一些常用组件。此篇文章为un...
    任建堃阅读 19,318评论 0 28
  • uni-app跨平台框架官方教程 链接:https://ke.qq.com/course/343370 一、框架简...
    Neyo_凉阅读 36,088评论 0 43
  • 一、项目结构介绍 pages.json:配置页面路由、导航条、选项卡等页面类信息,详见。manifest.json...
    移动端_小刚哥阅读 2,781评论 0 4
  • 昨晚我有很多家务事,儿子又让我陪着去小区游乐场玩,如果我陪他下去玩家务活就干不了,如果我干家务活儿子就不能下去...
    星拱妈阅读 187评论 0 0