AVM
数据绑定
<view class="user-info">
<text class="name">{{userInfo.name}}</text>
</view>
data() {
return {
userInfo: {
name: 'lq'
},
};
},
样式不继承
.user-info {
/* 无效 */
color: #f00;
}
.name {
color: #1890ff;
}
所有组件默认flex布局
这是默认值
.list {
display: flex;
flex-direction: column;
}
实现每一项水平居中
<view class="list">
<text>item 1</text>
<text>item 2</text>
<text>item 3</text>
</view>
.list {
align-items: center;
}
CSS选择器只可以用id、class、element这三种
条件渲染
<view>
<text v-if="userInfo.name">{{userInfo.name}}</text>
<text v-else>暂未登录</text>
</view>
事件监听
<button @click="onClick">click</button>
onClick() {
api.toast({
msg:'click'
})
},
循环渲染
<view v-for="(item, index) in items">
<text>{{index}}</text>
<text>{{item.name}}</text>
</view>
<view v-for="item of items">
<text>{{item.name}}</text>
</view>
通用性的语法
常用的提示API
api.alert({
title: 'testtitle',
msg: 'testmsg',
});
api.toast({
msg:'click'
})
api.confirm({
title: '提示',
msg: '是否退出?',
buttons: ['确定', '取消']
}, function(ret, err) {
var index = ret.buttonIndex;
// 点击确定,index为1,点击取消,index为2
});
打开一个有标题栏的页面
api.openTabLayout({
name: 'index',
url: '../index/index.stml',
title: "首页",
navigationBar: {
background: '#1890ff',
color: '#fff'
}
})
app设置底部导航条和顶部导航条 app.json放在项目根目录
{
"name": "root",
"navigationBar": {
"background": "#1890ff",
"color": "#fff",
"hideBackButton": true
},
"tabBar": {
"background": "#fff",
"shadow": "#fff",
"selectedColor": "#1890ff",
"color": "#999",
"frames": [{
"title": "首页",
"name": "index",
"url": "widget://pages/index/index.stml"
}, {
"title": "列表",
"name": "list",
"url": "widget://pages/list/list.stml"
}, {
"title": "我的",
"name": "me",
"url": "widget://pages/me/me.stml"
}],
"list": [{
"text": "首页",
"iconPath": "widget://image/me.png",
"selectedIconPath": "widget://image/me1.png"
}, {
"text": "列表",
"iconPath": "widget://image/me.png",
"selectedIconPath": "widget://image/me1.png"
}, {
"text": "我的",
"iconPath": "widget://image/me.png",
"selectedIconPath": "widget://image/me1.png"
}]
}
}
项目配置文件中进行配置 config.xml
<content src="app.json" />
设置底部导航条的角标
// 设置角标
api.setTabBarItemAttr({
index: 2, // 具体哪个页面的索引
badge: {
text: 3, // 非0即可,可以是空字符串
background: '#f00',
color: '#fff'
}
})
数据缓存到手机的文件系统中 设置数据
api.setPrefs({
key: 'name',
value: 'liqi'
});
读取数据
api.getPrefs({
key: 'name'
}, function(ret, err) {
var name = ret.value;
api.toast({
msg:name
})
});
删数据
api.removePrefs({
key: 'name'
});
数据存储在全局状态中,保存在内存中
api.setGlobalData({
key: 'age',
value: '24'
});
var age = api.getGlobalData({
key: 'age'
});
获取缓存大小,单位字节
api.getCacheSize(function(ret) {
var size = ret.size;
api.toast({
msg: 'size: ' + size
})
});
清除app缓存
api.clearCache(function() {
api.toast({
msg: '清除完成'
});
});
常用组件
<image src="../../image/me1.png"></image>
覆盖按钮样式
<button class="btn" type="submit" >提交</button>
.btn {
background-color: #1890ff;
color: #fff;
border: none;
margin: 8px;
}
swiper
<swiper id="swiper" autoplay>
<swiper-item reusable>
<view class="content">
<text>{{item.name}}</text>
</view>
</swiper-item>
</swiper>
apiready(){//like created
const swiper = document.getElementById('swiper')
swiper.load({
data: [{name: 'lq'}, {name: 'hy'}]
})
},
.content {
height: 400px;
background-color: #eee;
font-size: 40px;
}
scroll-view横向滚动
<scroll-view scroll-x scroll-y={false}>
<view class="content"><text>test 1</text></view>
<view class="content"><text>test 2</text></view>
<view class="content"><text>test 3</text></view>
</scroll-view>
scroll-view {
width: 100%;
}
.content {
height: 400px;
background-color: #eee;
font-size: 40px;
width: 100%;
}
list-view/cell/list-footer/refresh
<list-view id="list" >
<refresh state={refreshState} onstatechange={this.onRefreshStateChange}>
<text>{refreshText}</text>
</refresh>
<cell :data-blog="item" @click="onClick">
<view class="item">
<text class="title">{{item.title}}</text>
<text>更新时间:</text>
<text>{{item.updated_at}}</text>
</view>
</cell>
<refresh type="footer" state={loadState} onstatechange={this.onLoadStateChange}>
<text>{loadText}</text>
</refresh>
<list-footer>
<view><text>没有更多数据了</text></view>
</list-footer>
</list-view>
data() {
return{
page: 1,
pageSize: 10,
list: [],
refreshState: 'normal',
refreshText: '下拉刷新',
loadState: 'normal',
loadText: '上拉加载'
}
},
onRefreshStateChange(e) {
const state = e.detail.state;
const that = this;
if (state == 'normal') {
this.data.refreshState = 'normal';
this.data.refreshText = '下拉刷新'
} else if (state == 'dragging') {
this.data.refreshState = 'dragging';
this.data.refreshText = '下拉刷新2'
} else if (state == 'refreshing') {
this.data.refreshState = 'refreshing';
this.data.refreshText = '刷新中...'
setTimeout(function(){
that.data.refreshState = 'normal';
that.data.refreshText = '下拉刷新'
}, 3000);
}
},
onLoadStateChange(e) {
const state = e.detail.state;
const that = this;
if (state == 'normal') {
this.data.loadState = 'normal';
this.data.loadText = '上拉加载'
} else if (state == 'dragging') {
this.data.loadState = 'dragging';
this.data.loadText = '上拉加载2'
} else if (state == 'refreshing') {
this.data.loadState = 'refreshing';
this.data.loadText = '加载中...'
setTimeout(function(){
that.data.loadState = 'normal';
that.data.loadText = '上拉加载'
}, 3000);
}
},
frame 内部显示网页或本地页面 safe-area 用来保证页面一定会显示在安全区域
<template name='list'>
<view>
<safe-area>
<frame class="frame" url="https://www.baidu.com"></frame>
</safe-area>
</view>
</template>
组件化开发 定义一个组件,接收props,注册点击事件,触发父组件监听的自定义事件,并传参
<template name="news-item">
<view onclick="onclick">
<text>{{news.title}}</text>
<text>{{news.content}}</text>
</view>
</template>
<script>
export default {
name: "news-item",
props: {
news: Object
},
data: function() {
return {
}
},
methods: {
onclick() {
this.fire('clickMe', this.news)
}
}
}
</script>
定义父组件或者父页面,导入组件并传递props,监听自定义事件
<template name='list'>
<view class="page">
<news-item :news="news" onclickMe="onClick" />
<news-item :news="news" />
<news-item :news="news" />
</view>
</template>
<script>
import '../../components/news-item/news-item.stml'
export default {
name: 'list',
data() {
return{
news: {
title: 'test',
content: 'test content'
}
}
},
methods: {
onClick(e) {
api.toast({
msg: e.detail.content
})
}
}
}
</script>
<style>
</style>
显示隐藏默认loading动画
api.showProgress({
title: '加载中...',
modal: false
});
api.hideProgress()
打电话
api.call({
number:'17730121655'
})
发短信
api.sms({
numbers:['17730121655'],
text:'你好!'
})
网络请求
api.ajax({
url: ''
}, function(ret, err) {
});
UI库 vant
版本热更新 云修复
<preference name="autoUpdate" value="true" />
<preference name="smartUpdate" value="true" />
api.addEventListener({
name:'smartupdatefinish'
}, function(ret, err){
alert('云修复完成');
api.rebootApp();
});
极光推送
<feature name="ajpush">
<param name="channel" value="developer-apicloud" />
<param name="app_key" value="90f9e5e27aa417dc373dfff4" />
</feature>
var ajpush = api.require('ajpush');
ajpush.init(function(ret) {
if (ret && ret.status){
console.log("极光初始化成功!")
}
});
ajpush.setListener(
function(ret) {
var id = ret.id;
var title = ret.title;
var content = ret.content;
var extra = ret.extra; // 键值对
api.setGlobalData({
key: 'blogNumber',
value: ret.extra.number
});
api.openTabLayout({
name: 'blog',
url: './blog.html',
title: "博客详情",
navigationBar: {
background: '#1890ff',
color: '#fff'
}
})
}
);
闪光灯
const DVTorch = api.require('DVTorch');
const vm = new Vue({
el: '#app',
data: {
status: false,
text: '打开闪光灯'
},
methods: {
setLight() {
if (this.status) {
this.status = false;
this.text = '打开闪光灯'
} else {
this.status = true;
this.text = '关闭闪光灯'
}
DVTorch.toggle({
});
}
}
})
有一个 index.html App 的入口文件,再加上 FrameGroup 切换
api.openFrameGroup ({
name: 'tabs',
scrollEnabled:true,
rect:{x:0, y: 0, w:'auto', h: 800},
index:0,
// preload:4,
frames:
[
{
name: 'page1',
url: 'page1.html',
},{
name: 'page2',
url: 'page2.html',
bounces:false
}
]
}, function(ret, err){
// vm.tab = ret.index
})
api.closeFrame()
api.openFrame({
name: 'page2',
url:'./page2.html',
rect: {
x: 0,
y: 0,
w: 'auto',
h: 300
}
})
设置剪切板内容
const clipBoard = api.require('clipBoard');
clipBoard.set({
value: 'test value'
}, function(ret, err) {
if (ret) {
if (ret.status) {
api.toast({
msg: '复制成功'
})
} else {
api.toast({
msg: '复制失败'
})
}
} else {
api.toast({
msg: '复制失败'
})
}
});
读取剪切板内容
clipBoard.get(function(ret, err) {
if (ret) {
if (ret.value) {
api.toast({
msg: ret.value
})
} else {
api.toast({
msg: '获取剪切板失败'
})
}
} else {
api.toast({
msg: '获取剪切板失败'
})
}
});
使用 ACScanner 模块进行扫码
const ACScanner = api.require('ACScanner');
const that = this;
ACScanner.openScan({
// 扫描组件默认全屏
// 扫描框大小颜色
scanAnim: {
w:240,
h:240,
framColor: "#1890ff",
lineColor: "#1890ff"
},
scanType: 1, // 1/二维码,2/条形码,3/全部类型(默认)
scanStill: true, // 是否连续扫描
isDrawQRCodeRect: true, // 二维码自动对焦
}, function(ret, err) {
if (ret) {
if (ret.content) {
api.toast({
msg: ret.content
})
that.data.code = ret.content
ACScanner.closeScan({})
}
} else {
api.toast({
msg: '扫码失败'
})
}
});
UILineChart