uniapp页面样式和布局和nvue教程
尺寸单位
uni-app
支持的通用 css
单位包括 px
、rpx
px
即屏幕像素。rpx
即响应式px
,一种根据屏幕宽度自适应的动态单位。以750
宽的屏幕为基准,750rpx
恰好为屏幕宽度。屏幕变宽,rpx
实际显示效果会等比放大。但在App
端和H5
端屏幕宽度达到960px
时,默认将按照375px
的,屏幕宽度进行计算,具体配置参考:rpx计算配置
rpx
详细说明:
设计师在提供设计图时,一般只提供一个分辨率的图。严格按设计图标注的 px
做开发,在不同宽度的手机上界面很容易变形。而且主要是宽度变形。高度一般因为有滚动条,不容易出问题。由此,引发了较强的动态宽度单位需求。微信小程序设计了 rpx
解决这个问题。 uni-app
在 App
端、H5
端都支持了 rpx
,并且可以配置不同屏幕宽度的计算方式,具体参考:rpx计算配置。
rpx
是相对于基准宽度的单位,可以根据屏幕宽度进行自适应。uni-app
规定屏幕基准宽度 750rpx
。
开发者可以通过设计稿基准宽度计算页面元素 rpx
值,设计稿 1px
与框架样式 1rpx
转换公式如: 设计稿 1px / 设计稿基准宽度 = 框架样式 1rpx / 750rpx
。
换言之,页面元素宽度在 uni-app
中的宽度计算公式:750 * 元素在设计稿中的宽度 / 设计稿基准宽度
页面元素宽度在 uni-app
中的宽度计算举例说明:
- 若设计稿宽度为 750px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 uni-app 里面的宽度应该设 为: 750 * 100 / 750 ,结果为:100rpx。
- 若设计稿宽度为 640px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 uni-app 里面的宽度应该设 为: 750 * 100 / 640 ,结果为:117rpx。
- 若设计稿宽度为 375px,元素 B 在设计稿上的宽度为 200px,那么元素 B 在 uni-app 里面的宽度应该设 为: 750 * 200 / 375 ,结果为:400rpx。
注意 :
rpx
是和宽度相关的单位,屏幕越宽,该值实际像素越大。如不想根据屏幕宽度缩放,则应该使用 px
单位。如果开发者在字体或高度中也使用了 rpx
,那么需注意这样的写法意味着随着屏幕变宽,字体会变大、高度会变大。如果你需要固定高度,则应该使用px
,rpx
不支持动态横竖屏切换计算,使用rpx
建议锁定屏幕方向。
全局样式与局部样式
定义在 App.vue
中的样式为全局样式,作用于每一个页面。在 pages
目录下 的 vue
文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 App.vue
中相同的选择器。
注意:
App.vue
中通过 @import
语句可以导入外联样式文件,一样作用于每一个页面。
<style>
/*每个页面公共css */
@import url("../../common/css/common.css");
</style>
效果:
APP
和小程序中子组件会使用父组件的样式,H5
端不会使用父组件的样式。
CSS变量
uni-app
提供内置 CSS
变量
CSS 变量 | 描述 | App | 小程序 | H5 |
---|---|---|---|---|
–status-bar-height | 系统状态栏高度 | 系统状态栏高度 | 25 | 0 |
–window-top | 内容区域距离顶部的距离 | 0 | 0 | NavigationBar 的高度 |
–window-bottom | 内容区域距离底部的距离 | 0 | 0 | TabBar 的高度 |
注意:
var(--status-bar-height)
此变量在微信小程序环境为固定25px
,在App
里为手机实际状态栏高度。- 当设置
"navigationStyle":"custom"
取消原生导航栏后,由于窗体为沉浸式,占据了状态栏位置。此时可以使用一个高度为var(--status-bar-height)
的view
放在页面顶部,避免页面内容出现在状态栏。 - 由于在
H5
端,不存在原生导航栏和tabbar
,也是前端div
模拟。如果设置了一个固定位置的居底view
,在小程序和App
端是在tabbar
上方,但在H5
端会与tabbar
重叠。此时可使用--window-bottom
,不管在哪个端,都是固定在tabbar
上方。 - 目前
nvue
在App
端,还不支持--status-bar-height
变量,替代方案是在页面onLoad
时通过uni.getSystemInfoSync().statusBarHeight
获取状态栏高度,然后通过style
绑定方式给占位view
设定高度。
示例:
<template>
<view>
<view class="status_bar">
<!-- 这里是状态栏 -->
</view>
<view> 状态栏下的文字 </view>
</view>
</template>
<style>
.status_bar {
height: var(--status-bar-height);
width: 100%;
background: red;
}
</style>
效果:
<template/>
和 <block/>
uni-app
支持在 template
模板中嵌套 <template/>
和 <block/>
,用来进行 列表渲染
和 条件渲染
。
<template/>
和 <block/>
并不是一个组件,它们仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
<block/>
在不同的平台表现存在一定差异,推荐统一使用 <template/>
。
<template>
<view>
<view class="box">
<template v-if="test">
<view>test为true,</view>
<view>test为true</view>
</template>
<template v-else>
<view>test为false,</view>
<view>test为false</view>
</template>
</view>
</view>
</template>
<script>
export default {
data() {
return {
test: false,
}
}
}
</script>
<style>
.box {
display: flex;
}
</style>
效果:
Flex
布局
为兼容多端跨平台运行,建议使用flex布局进行开发
阮一峰的flex教程:flex教程
{
display: flex;
flex-direction: row;
}
flex-direction
决定主轴的方向(即项目的排列方向)
flex-wrap
默认情况下,项目都排在一条线(又称"轴线")上。
flex-wrap
属性定义,如果一条轴线排不下,如何换 行。
flex-flow
是flex-direction
属性和flex-wrap属性的简写形式,默认值为row nowrap
。
justify-content
定义了项目在主轴上的对齐方式。
align-items
定义项目在交叉轴上如何对齐。
align-content
定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
nvue 教程
uni-app App
端内置了一个基于 weex
改进的原生渲染引擎,提供了原生渲染能力。在 App
端,如果使用 vue
页面,则使用 webview
渲染;如果使用 nvue
页面(native vue
的缩写),则使用原生渲染。一个 App
中可以同时使用两种页面,比如首页使用 nvue
,二级页使用 vue
页面,hello uni-app
示例就是如此。
虽然 nvue
也可以多端编译,输出 H5
和小程序,但 nvue
的 css
写法受限,所以如果你不开发 App
,那么不需要使用 nvue
。
以往的 weex
,有个很大的问题是它只是一个高性能的渲染器,没有足够的 API
能力(比如各种 push sdk
集成、蓝牙等能力调用),使得开发时非常依赖原生工程师协作,开发者本来想节约成本,结果需要前端
、iOS
、Android
3 拨人开发,适得其反。 nvue
解决了这个问题,让前端工程师可以直接开发完整 App
,并提供丰富的插件生态和云打包。这些组合方案,帮助开发者切实的提高效率、降低成本。
如果一个页面路由下同时有vue
页面和nvue
页面,即出现同名的vue
和nvue
文件。那么在App
端,会仅使用nvue
页面,同名的vue
文件将不会被编译到App
端。而在非App
端,会优先使用vue
页面。
nvue
开发与vue
开发的常见区别
基于原生引擎的渲染,虽然还是前端技术栈,但和web开发肯定是有区别的。
nvue
页面控制显隐只可以使用v-if
不可以使用v-show
nvue
页面只能使用flex
布局,不支持其他布局方式。页面开发前,首先想清楚这个页面的纵向内容有什么,哪些是要滚动的,然后每个纵向内容的横轴排布有什么,按flex
布局设计好界面。nvue
页面的布局排列方向默认为竖排(column
),如需改变布局方向,可以在manifest.json
->app-plus
->nvue
->flex-direction
节点下修改,仅在uni-app
模式下生效。nvue
页面编译为H5
、小程序
时,会做一件css
默认值对齐的工作。因为weex
渲染引擎只支持flex
,并且默认flex
方向是垂直。而H5
和小程序
端,使用web
渲染,默认不是flex
,并且设置display:flex
后,它的flex
方向默认是水平而不是垂直的。所以nvue
编译为H5
、小程序
时,会自动把页面默认布局设为flex
、方向为垂直
。当然开发者手动设置后会覆盖默认设置。- 文字内容,必须、只能在
<text>
组件下。不能在<div>
、<view>
的text
区域里直接写文字。否则即使渲染了,也无法绑定js
里的变量。 - 只有
text
标签可以设置字体大小,字体颜色。 - 布局不能使用百分比、没有媒体查询。
nvue
切换横竖屏时可能导致样式出现问题,建议有nvue
的页面锁定手机方向。- 支持的
css
有限,不过并不影响布局出你需要的界面,flex
还是非常强大的。 - 不支持背景图。但可以使用
image
组件和层级来实现类似web
中的背景效果。因为原生开发本身也没有web
这种背景图概念 css
选择器支持的比较少,只能使用class
选择器。nvue
的各组件在安卓端默认是透明的,如果不设置background-color
,可能会导致出现重影的问题。class
进行绑定时只支持数组语法。Android
端在一个页面内使用大量圆角边框会造成性能问题,尤其是多个角的样式还不一样的话更耗费性能。应避免这类使用。nvue
页面没有bounce
回弹效果,只有几个列表组件有bounce
效果,包括list
、recycle-list
、waterfall
。- 原生开发没有页面滚动的概念,页面内容高过屏幕高度并不会自动滚动,只有部分组件可滚动(
list
、waterfall
、scroll-view/scroller
),要滚得内容需要套在可滚动组件下。这不符合前端开发的习惯,所以在nvue
编译为uni-app
模式时,给页面外层自动套了一个scroller
,页面内容过高会自动滚动。(组件不会套,页面有recycle-list
时也不会套)。 - 在
App.vue
中定义的全局js
变量不会在nvue
页面生效。globalData
和vuex
是生效的。 App.vue
中定义的全局css
,对nvue
和vue
页面同时生效。如果全局css
中有些css
在nvue
下不支持,编译时控制台会报警,建议把这些不支持的css
包裹在条件编译里,APP-PLUS-NVUE
- 不能在
style
中引入字体文件,nvue
中字体图标的使用参考:加载自定义字体。如果是本地字体,可以用plus.io
的API
转换路径。 - 目前不支持在
nvue
页面使用typescript/ts
。 nvue
页面关闭原生导航栏时,想要模拟状态栏,可以参考文章。但是,仍然强烈建议在nvue
页面使用原生导航栏。nvue
的渲染速度再快,也没有原生导航栏快。原生排版引擎解析json
绘制原生导航栏耗时少,而解析nvue
的js
绘制整个页面的耗时要大的多,尤其在新页面进入动画期间,对于复杂页面,没有原生导航栏会在动画期间产生整个屏幕的白屏或闪屏。
样式
nvue
的css
仅支持flex
布局,是webview
的css
语法的子集。这是因为操作系统原生排版不支持非flex
之外的web
布局。当然flex
足以排布出各种页面,只是写法需要适应。- 在选择器方面支持的较少,只支持简单的
class="classA"
。class
进行绑定时只支持数组语法。- 不支持媒体查询。
- 不支持复合样式,不支持简写。
- 不能在
style
中引入字体文件。- 布局不能使用百分比,如
width:100%;
。- 有些
web
的css
属性在nvue
里无法支持,比如背景图。但可以使用image
组件和层级来实现类似web
中的背景效果。因为原生开发本身也没有web
这种背景图概念。nvue
的各组件在安卓端默认是透明的,如果不设置background-color
,可能会导致出现重影的问题。- 文字内容,必须只能在
text
组件下,text
组件不能换行写内容,否则会出现无法去除的周边空白。- 只有
text
标签可以设置字体大小,字体颜色。
nvue
和 vue
相互通讯
uni.$emit(eventName,OBJECT)
触发全局的自定事件。附加参数都会传给监听器回调。
eventName
类型String
事件名,OBJECT Object
触发事件携带的附加参数。
代码示例
uni.$emit('update',{msg:'页面更新'})
uni.$on(eventName,callback)
监听全局的自定义事件。事件可以由 uni.$emit 触发,回调函数会接收所有传入事件触发函数的额外参数。
示例:vue
对nvue
的传值通讯
index.vue
页面代码
<template>
<view>
<button @click="sendMessage">点击修改数据</button>
</view>
</template>
<script>
export default {
data() {
return {
message: 'Hello from nVue'
};
},
methods: {
sendMessage() {
uni.navigateTo({
url: '../test/test',
success: () => {
// 确保目标页面已经加载
uni.$emit('ceshi', {
title: '测试标题',
content: '测试内容'
});
}
});
}
}
};
</script>
test.nvue
页面代码
<template>
<view>
<text>Test Page</text>
</view>
</template>
<script>
export default {
onLoad() {
// 注册事件监听器
uni.$on('ceshi', (data) => {
console.log('标题:' + data.title);
console.log('内容:' + data.content);
});
},
onUnload() {
// 页面卸载时移除事件监听器
uni.$off('ceshi');
},
methods: {}
};
</script>
<style scoped>
/* 可以在这里添加样式 */
</style>
效果:
uni.$once(eventName,callback)
监听全局的自定义事件。事件可以由uni.$emit
触发,但是只触发一次,在第一次触发之后移除监听器。
属性 | 类型 | 描述 |
---|---|---|
eventName | String | 事件名 |
callback | Function | 事件回调函数 |
示例代码: |
onLoad() {
uni.$once('update',function(data){
console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);
})
}
示例:
<template>
<view>
<text>Test Page</text>
</view>
</template>
<script>
export default {
onLoad() {
uni.$once('ceshi', function(data) {
console.log('监听到事件来自 update ,携带参数 msg 为:' + data);
})
},
onUnload() {
// 页面卸载时移除事件监听器
uni.$off('ceshi');
},
methods: {}
};
</script>
<style scoped>
/* 可以在这里添加样式 */
</style>
效果:
uni.$off([eventName, callback])
移除全局自定义事件监听器。
属性 | 类型 | 描述 |
---|---|---|
eventName | Array[String] | 事件名 |
callback | Function | 事件回调函数 |
示例代码 |
onUnload() {
// 移除 update 监听器
uni.$off('update')
}
上面中已经用到了uni.$off
的使用,在每次onUnload
页面卸载的时候移除事件监听。
Tips
- 如果没有提供参数,则移除所有的事件监听器;
- 如果只提供了事件,则移除该事件所有的监听器;
- 如果同时提供了事件与回调,则只移除这个回调的监听器;
- 提供的回调必须跟
$on
的回调为同一个才能移除这个回调的监听器;
阶段完结~