前言
uni-app
作为一个良好的跨平台工具,被广泛应用于开发h5、小程序、app等,其中最多应该应用在小程序、h5
了,其可以减少不同平台的开发时间,可以说非常棒(就算是应用到一个平台作为一个技术解决方案也是很不错的)
其主要使用 vue
那套开发逻辑,且使用起来和微信小程序像的很,因此入门很快,不懂的还可以到这里面看,搜索 uni-app官网 、vue文档、测试案例demo
下面就通过新建项目开始,来介绍常用的一些东西
ps
:这里只引导开发过web
或者小程序
的,小白到连UI等基础也不会的,就不要过来了😂
ps2
:下面的介绍主要针对于小程序开发,其他的自行根据情况调整即可
ps3
:uni-app 中文件名
、css名
基本上都是以 -
作为多个词汇的间隔符,以代替蛇形、驼峰,避免了很多问题,js变量仍然以蛇形和驼峰为主,也和官方组件的格调一致
创建一个 uni-app 项目
新建 uni-app
项目,选择 uni-ui
项目,然后选择 vue3
ps : uni-ui
是因为避免了基本ui组件导入,且能给我们后续组件
使用编写带来便利,非常方便;另外,新项目能使用vue3
,最好使用vue3
,毕竟据说性能
有提升
创建完后,应该长成下面这样子(package.json是后面添加的,后面再说)
我们可以看到 uni-modules
特色的组件,其默认开启easycom
模式,在这里面,不引用,可以直接使用,且没有使用到的组件也不会被打包进去,力推
接下来配置 manifest.json
,其中 uni-app 应用标识,需要到 uni-app平台申请,没有点击获取注册就可以了,跟其他平台一样,不多介绍
上面的基础配置配置完毕后,就根据我们的平台配置就可以了,下面以微信小程序为例,进行简单配置(不配置调试不了哈)
就这样我们的项目就算初步建成了
文件相关简介与部分配置
文件相关我们主要介绍下面这些,一些后面会在基础开发和组件等展开介绍
pages
文件夹是开发页面的目录,有xml、script、css等,在同一个页面
static
为静态资源路径(图片、字体等)
uni_modules
为符合uni_modules
规范的组件文件夹,后面会具体介绍(无论是三方还是自定义组件这里都很重要,主要是方便简洁),然后是其他的,下面一个一个简单介绍
ps
:其中 my-component
是我创建的属于自己项目的组件,后续会介绍,其他的是创建项目时带入的
manifest.json
其就是基础配置用的,用于配置 uni-app
或者一些平台调试打包
的参数,很简单不多介绍
page.json
配置导航路由、组件、tabbar、easycom等组件相关参数的如下所示,一目了然,自己创建完毕后就知道咋回事了(后面还会稍微详细点介绍),如下图所示
App.vue
为我们实际解除项目的开始(实际上更早的应该在main
),这是进入小程序后会走的几个方法,很实用(onLaunch这个属于应用启动时走的,正常页面用的onLoad,详细可以看后面的生命周期)
ps
:细心的可能注意到 style
中 lang='scss'
,其就是设置 scss
模式的,当然也可以支持less
,基础的 css
更没问题了
uni.scss
为系统给我们提供的全局样式文件,和 css、less 类似,其和less一样可以很方便的定义全局css变量、选择器
等,且不引用可以直接在xml
中使用,与定义在 App.vue
中的style
样式一样,可以全局使用,和微信小程序类似
package.json、node_modules
是前端开发基本都会用到的,通过 package.json
配置,使用 npm、yarn
引入三方到 node_modules
文件夹,这个后面引入组件和 easycom
配置再详细介绍
全局参数相关配置
全局配置,实际上上面介绍的都差不多了,这里面再详细介绍一下
uni.scss
为系统给我们预留的一个全局样式文件,且为 scss 模式,因此支持很方便的全局变量定义,选择器使用,甚至嵌套都有可能(但不建议全局嵌套,可读性差),我们只需要加入一些常用属性、选择器样式即可
App.vue
则是我们实际接触开发的第一个vue
文件了,和小程序系列开发类似,在script
中,我们可以定义一些全局变量,更加方便我们使用,同时,scss
样式中,我们也可以像创建一些全局 scss变量、选择器
等,需要用到另外一些 scss
文件,也可以 @import
的方式导入即可(例如:我们有一些组件的公用样式
,可以导入)
组件生命周期与注意项
小程序组件生命周期和vue组件生命周期不同,uni-app主要开发小程序,因此首推小程序的生命周期(小程序运行时,vue的一些生命周期是不会走的,这点可以自行尝试)
小程序常用生命周期(推荐
),vue的生命周期就不多介绍了,要用可以参考上面入口,用的比较多的就是 mounted、unmounted了,其他的有时候不会调用哈
js
<script>
export default {
data() {
return {
name: 'marshal',
age: 40,
}
},
//vue生命周期中推荐
mounted() {
// 渲染之后调用,一般逻辑在这里,调用一次
console.log('mounted')
},
//app小程序端推荐,web端不一定走
onLoad() {
// 渲染之后调用,一般逻辑在这里,调用一次
console.log('onLoad')
},
//小程序使用
onShow() {
//在 onLoad之后调用,或者 keep-alive 缓存被激活时调用
//比 activated 初次进入多走了一步,这是需要注意的地方
console.log('onShow')
},
onUnload() {
// 卸载之后调用,移除监听等操作在这里
console.log('onUnload')
},
methods: {
}
}
</script>
基础页面开发(包含tabbar、资源路径等)
开发我们项目页面时,只需要创建好文件夹,然后点击右键,选择新建页面
即可,编辑器会自动帮我们在 pages.json
中引入我们的页面,如下所示,
起好名字后会自动创建一个同名文件夹、文件,好处就是我们业务代码多的时候,一部分可以抽离到同层目录下,通过导入方式使用
ps
:起名最好跟系统一样使用,不采用驼峰和蛇形,使用 -
作为单词目录的间隔
创建好了之后,如下所示,xml、js、css开发位置一目了然,然后在里面开发吧
ps
:由于都在一个页面,所以代码长一些没办法的事情,可以使用组件 + 抽离公共组件 + 抽离业务等方式来缩减单文件代码
tabbar
tabbar
在我们前面介绍的 pages.json
文件中
js
//到这里相信不需要我过多介绍了吧
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#3cc51f",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/index/index",
"iconPath": "static/c1.png",
"selectedIconPath": "static/c2.png",
"text": "首页"
}, {
"pagePath": "pages/user/user",
"iconPath": "static/c3.png",
"selectedIconPath": "static/c4.png",
"text": "我的"
}]
},
绑定参数、绑定事件
静态绑定
直接传入内容即可,无论是字符串还是数字等
js
<image src="@/static/c1.png"></image>
动态绑定参数
只需要在属性前面加入 :
即可完成绑定,外部属性变化会传递到组件内部,以完成更新
绑定事件
只需要加入 @
即可,内部的事件会反馈给外面指定方法,即算绑定成功
如下所示
js
<template>
<view class="container">
<dy-double-button :name="dName" @valueChanged="onComponentChanged" />
<view @click="onUpdateName">点击我从外部更新desc</view>
</view>
</template>
<script>
export default {
data() {
return {
name: 'marshal绑定',
}
},
methods: {
onComponentChanged(e) {
console.log(e)
},
onUpdateName() {
this.name = '哈哈哈哈哈哈'
},
}
}
</script>
资源路径
资源路径的引用主要以 绝对路径、相对路径
的方式来引入
js
//绝对路径,通过根目录下的某个文件夹开始直接引入
<image src="@/static/c1.png"></image>
//相对于当前文件位置引入文件(用的最舒服的就是组件同级目录下,引用自己的图片、代码逻辑文件等)
<image src="../../static/c2.png"></image>
显示字符参数
与上面不同的是,显示字符不需要绑定之类的,只需要直接填充即可,如果需要显示或者嵌入某个字符串,可以使用双大括号
方式引入变量,即: {{ 变量 }}
,这个跟微信小程序一样的
js
<text>总年龄:{{totolAge}}</text>
<text>{{totolAge}}</text>
v-if、v-else-if、v-else、
主要是一个判断语句
js
<view v-if="status===1">我成功了</view>
<view v-else-if="status===2">我失败了</view>
<view v-else>我都没参加</view>
注意 :不建议跟 v-for
同时使用,vue2
中 v-for
优先级高,vue3
中 v-if
优先级高
v-for
常见的遍历语句,可以生成 list
,另外如果需要提高性能,需要设置:key
,可以加入唯一值,也可以直接使用索引,能避免更新时频繁创建 item
js
<view v-for="(item, index) in listData" :key="index">
<text>第{{index + 1}}个元素是:{{item}}</text>
</view>
css支持配置(scss、less)
只需要设置 style
的 lang
属性即可,需要支持 scss
就设置成 scss
,需要支持 less
就设置成 less
即可,当然也可以设置成 css
, 非常方便,这里就不多介绍了,需要学习前两个的可以搜一下
js
<!-- 设置 lang="scss" 就支持 scss 的内容了 -->
<style lang="scss">
//设置单个页面背景
page {
width: 100%;
height: 100%;
}
</style>
data、template、style
data
就是我们的 state
状态机,我们可以通过修改 data
的参数来更新内容, template
就是xml
组件,style
就是 css
,支持 less、scss
通过 this.data属性名
可以修改 data
内容 和显示
内容
js
<template>
<view class="container">
<text class="large-size theme-color">{{啦啦啦}}</text>
</view>
</template>
<script>
export default {
data() {
return {
name: '啦啦啦'
};
},
methods: {
onUpdate() {
this.name = '哈哈' //通过 this.name 可以修改内容和现实
},
}
}
</script>
<style>
.container {
width: 100%;
height: 100%;
}
</style>
computed 属性计算
当我们的某个显示内容,可能要依赖于其他 data
字段而变化时,我们可以通过 computed
来解决,computed
与 data
字段同级
js
computed: {
//直接编写的的是get方法,在xml使用时,就像在 data 中使用字段一样
//且会根据依赖项的改变而改变
averageAge() {
return (this.dAge + this.age) / 2
},
//可以分开定义set和get方法
totolAge: {
get() {
return this.dAge + this.age
},
//当我们需要设置我们的计算项时,也可以根据新值给依赖项赋值,这就是 set 方法的秒用了
set(newVal) {
let half = newVal / 2
this.dAge = half
this.age = newVal - half
}
},
},
//使用起来和 data 的字段一样哈
<text>总年龄:{{totolAge}}</text>
<text>平均年龄:{{averageAge}}</text>
watch 属性监听
watch
属性监听,用于监听一个值是否发生变化,某种程度上可以被 computed
代替,实际使用也不是很多,大多可以被 computed
很舒服地替代,且一般在组件开发用的多
js
watch: {
//使用watch来响应数据的变化,第一个参数为newVal新值,第二个参数oldVal为旧值
name: function(newVal, oldVal) {
console.log("a--newVal: ", newVal, "a--oldVal: ",oldVal);
},
age: function(newVal, oldVal) {
console.log("b--newVal: ", newVal, "b--oldVal: ",oldVal);
}
},
methods
methods
与 data
同级,我们平时写的自定义函数都是在这里面(处理系统的生命周期函数,还有上面的一些固定声明),包括我们的监听回调等基本都在这里编写
js
<script>
export default {
data() {
return {
name: '哈哈',
};
},
methods: {
onLogin() {
},
}
}
</script>
javascript抽离逻辑文件并导入(import)
UI组件我们可以以组件方式抽离,但复杂的业务往往是万恶之源
当我们主模块业务较多时,可以抽离出来一份业务逻辑,并将其抽离到合适位置(私用在page同名文件夹下即可,公用可以另起一个全局公用文件夹即可)
如下所示,抽离出代码,右键点击新建,创建vue文件(注意不是页面,页面会在pages.json创建目录)
然后只留下 script
标签即可,在 export default
里面创建暴露方法即可
js
//在使用的script中导入
import smallF from './small-function.vue'
//调用即可
smallF.getOtherInfo()
css导入 import
js
@import '@/uni_modules/uni-scss/index.scss';
设置单个页面背景大小
和全局 page
类似,只需要在单个页面 page
设置即可
js
---单个页面的css---
//设置单个页面背景,添加css选择器
page {
width: 100%;
height: 100%; //这样页面就会被拉伸满了,注意滚动视图一般不这么推荐,否则可能会出现滑动障碍
}
设置导航和单个页面下拉刷新功能
js
//全局样式
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"app-plus": {
"background": "#efeff4"
}
}
js
onPullDownRefresh() {
setTimeout(function() {
//不能一直刷新到最长时间,成功过后,注意调用方法立即停止下拉刷新动画
uni.stopPullDownRefresh()
}, 500)
},
全局样式(导航、状态栏、标题、窗口背景色)
用于设置应用的状态栏、导航条、标题、窗口背景色 -- 入口
js
//常用的就下面几个了
"globalStyle": {
"navigationBarTextStyle": "black", //导航文字颜色
"navigationBarTitleText": "uni-app", //导航默认标题
"navigationBarBackgroundColor": "#F8F8F8", //导航背景颜色
"backgroundColor": "#F8F8F8", //下拉出来的背景颜色
}
导航、传值、页面栈
导航
其中用的最多的就是uni.navigateTo、uni.redirectTo、uni.reLaunch、uni.switchTab、uni.navigateBack
了 --- 入口
uni.navigateTo
:跳转到某一个页面
js
uni.navigateTo({
url: '/pages/login/login'
})
uni.redirectTo
:关闭当前页面,跳转到应用内的某个页面
js
//假设想从 help1 跳转到 help2,类似的,为了避免打开过多页面,可以替换页面
uni.redirectTo({
url: '/pages/help/help2'
});
uni.reLaunch
:关闭所有页面,打开到应用内的某个页面,能减少页面栈,常用于启动页到其他页面
uni.switchTab
:跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
uni.navigateBack
:返回到页面栈上一个页面,其中有一个 delta 参数,可以控制返回的页面数,有时配合页面栈用起来会更舒服
传值
这里介绍就以 navigateTo
为例,其他的有的不支持有的类似
方式一
: 以 url 方式传递,快捷方便,缺陷也很明显,不支持回调,且数据长度很短,一些甚至只限制了几十个字符,一般传递个 id 就足够了
js
//跳转
onLogin() {
let name = 'marshal'
uni.navigateTo({
url: `/pages/login/login?name=${name}` //长度受限不推荐
})
}
//跳转的页面,在onLoad 的参数中可以获取到 url 中的参数
onLoad(options) {
console.log('拼接url传递的会在这里作为参数显示,适合短字段', options)
}
方式二
:使用 eventChannel 传递(和微信小程序一模一样),支持传递大对象,支持回调
js
//跳转
onLogin() {
let name = 'marshal'
uni.navigateTo({
url: '/pages/login/login',
events: {
//需要回调方法在这里面编写
loginCallback: function(e) {
console.log(e)
}
},
success: function(res) {
//在这里传递参数,使用 eventChannel
res.eventChannel.emit('onLogin', name)
}
})
}
//跳转的页面,在onLoad 的参数中可以获取到 url 中的参数
onLoad(options) {
//获取 eventChannel,然后添加监听即可
let eventChannel = this.getOpenerEventChannel()
//小程序可能存在直接通过扫码定位到某个页面,因此存在不能获取到 eventChannel 的情况
// 此时添加监听会直接报错,因此可以通过判断避免
eventChannel && eventChannel.on && eventChannel.on('onLogin', function(res) {
console.log(res)
})
}
页面栈
当我们导航的时候会存在一个页面栈,用来保存或者恢复之前某一个页面使用的,因此了解其可以帮助我们返回到指定的页面,或者是做到特殊的功能
js
//获取当前页面栈
let pages = getCurrentPages()
console.log(pages)
//查看栈顶元素
let page = pages[pages.length-1]
console.log(page, page.route) //page.route 就是页面的path,可以打印看看
//ps: getCurrentPages配合selectorQuery可以在自定义弹窗时使用特别的舒服
部分应用
有时同一个使用 uni.navigateBack
返回的时候,不是返回上一个页面,而是返回到指定页面
如果返回页面数量固定的话,那么我们可以通过写死 delta
参数来确定返回的页面数
当中间页面不固定,就需要返回到指定页面的时候,我们就需要 getCurrentPages()
来确定我们是哪一种情况了,这样能够避免情况判断参数的传递,通过getCurrentPages()
的数量与指定页面等参数,来确定我们返回的页面数即可,这样就能准确的返回了
全局监听传值
uni.$emit(eventName,OBJECT)
触发全局的自定义事件。附加参数都会传给监听器回调
js
uni.$emit('update', '页面更新了')
uni.$on(eventName,callback)
js
uni.$on('update',function(data){
console.log('data');
})
uni.$off([eventName, callback])
移除全局自定义事件监听器
js
uni.$off('update')
uni.$once(eventName,callback)
监听全局的自定义事件,和 $on
类似,事件可以由 uni.$emit
触发,但是只触发一次
,在第一次触发之后移除监听器。
getCurrentPages、selectorQuery简介
getCurrentPages:获取页面栈数组,可以获取顶层或者下层页面对象(可以通过 page.route 获取页面path,用于判断)
selectorQuery:获取 page 某个页面节点,通过该方法定位页面,可以锁定某个页面内的某个组件
因此,他们两个搭配,可以获取到某个 page 页面内的某个组件,然后给该组件动态赋值或者添加回调,不可谓不爽,一般用于方便弹窗弹窗弹出
ini
--js--
//要是封装一下是不是很舒服
const query = uni.createSelectorQuery().in(this);
let context = query.select('#t-dialog')
if (context) {
context.data = defalutOptions;
context.confirmCallback = ...
context.cancelCallback = ...
}else {
...
}
获取到组件后,就可以对其动态操控了
--xml--
//赋予一个 id 选择器,方便查询
<component id="t-dialog" />
展示图片详情
只需要使用 uni.previewImage
方法就可以使用小程序平台特有的图片展示效果了(类似微信的点击图片放大),非常便捷
current、urls
为必填,支持单、多张图片,需要会注意的是 current
传入 url
时会被去重显示,而索引不会(从 0 开始)
扩展组件开发(component)与导入配置(两种)
组件开发有三种,一种是通过 uni_modules
创建的,一种是通过 npm
导入的三方符合标准的组件,一种是在自己文件夹下自己编写的
ps
:首推第一种,支持第二种,可以使用第三种,第一种不需要额外配置,后两种需要配置,但配置方法一样
实际上他们都很简单,这都是因为后面支持了 easycom
组件模式的缘故,升级到最新的 HBuilderX
就没问题了
下面先讲配置,然后再讲组件开发怎么相互传值使用的
uni_modules方法配置方式
使用该手段不需要额外配置,在刚开始我们创建 uni-ui
项目的时候,会自动给我们生成一个 uni_modules
目录 里面有 uni
系列的组件,会发现 easycom
下会自动扫描该目录,里面所有的组件可以直接使用
利用该效果,我们直接邮件 uni_modules
选择新建 uni_modules
插件即可,然后创建一个属于我们自己的组件库即可,然后在里面的 components
创建编写我们的一系列组件,然后向其他组件一样,直接使用即可,需要多个类型的就创建多个插件即可
ps
:需要注意的是使用 git 时,可别忽略 uni_modules 文件夹呀,不然自己的和 uni 模式的都没有了,哈哈,默认应该是忽略的(如果被别人忽略了,查找 .gitignore 删除 uni_modules 目录即可,并告诉那人别瞎搞😂)
上面我们创建了自己的组件插件,我们默认有一个同名组件,我们要不要都行,然后在创建一个我们自己的组件
外面调用也是直接使用即可,例如我们在主页调用它
npm导入和自建组件的配置方式
我们可以随意搭配使用,建议使用 dcloud
市场组件,还有自建组件
,npm 非必要不使用,一些不太符合规范的使用起来相对比较麻烦
npm 方式导入
npm
导入,假如以前是开发 vue 的,对于vue 的一些组件很喜欢,也可以通过 npm
方式导入使用,不过前提是它支持 easycom
的形式,不然很麻烦(需要一个一个导入,因此这里不教其他方式怎么引入的,参考 这里,反正不好用到我都懒得看🤣)
没有过 npm
的这里不介绍了,其他地方可以看,一顿操作后,我们导入了一个库,他的目录是下面这样的
除了 uni_modules
目录,其他的默认都不会扫描,因此需要我们自己配置,然后我们进入到 pages.json
文件中,通过 easycom
给我们的高效扫描模式,批量配置即可
如下所示,我们在 pages
页面路径同级下,粘贴如下代码,更改目录定位匹配到我们使用的组件即可,参考上面目录即可理解
js
// 例如: node_modules 中导入组件 uview-ui 组件
// 可以像如下所示编写
"easycom": {
"autoscan": true,
"custom": {
// 匹配node_modules内的uni组件
//uni- 为 uni- 开头的组件,后面的一样,$1动态匹配通前缀的第二个字符串(参考上图,uni-badge 的 badge)
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
配置完毕后,就可以直接使用了
自建组件配置
前面说了,我们自己新建的组件库配置和 npm
的一样,参考 npm
的配置,我们只需要将组件加入一个统一的前缀即可(asycom
下,默认配置的是全局模式
,因此最好不重名,不然涉及改名很麻烦)
我们做一个示范即可,最外层创建一个自己的 components
目录,然后在 pages
添加新的配置项即可,其实一看还挺简单的,参考下面,直接改一个前缀名就可以了哈
js
"easycom": {
"autoscan": true,
"custom": {
// 匹配自检的components里面的组件,my-为前缀
"^my-(.*)": "@/component/my-$1/my-$1.vue"
}
},
组件的使用和注意事项
接收属性 props
,在 data
的同级声明 props
, 一般我们都是直接设置默认值,或者什么都不设置
js
props: {
// 检测类型 + 其他验证
age: {
type: Number, //类型
default: 0, //默认值
required: true, //是否必传
validator: function(value) {
//校验传入的值
return value >= 0
}
},
name: {
type: String,
default: '',
required: true,
},
desc: String, //这样简写,可传可不传,默认undefined
},
props
接收的属性我们可以像 data
设定的参数一样 直接使用
,但是不可以在组件内部更改 props
如果想更改,直接在组件的 data
段接收值,然后内部使用即可,如果是依赖关系,需要使用 computed
js
data() {
//如果想更新值,在这里获取即可
return {
CAge: this.age,
cName: this.name,
}
},
对完传递属性,就想我们使用 view
的 @click
一样,我们需要这么做,在 data
的同级声明 emits
,对外暴露
js
//对外传递的事件名称
emits:['valueChanged'],
使用时传递事件名称 + 传递反馈对象参数即可
js
this.$emit('valueChanged', this.CAge)
外部调用组件时,这样即可正常使用了
js
<dy-double-button :name="name" :age="age" :desc="desc" @valueChanged="onComponentChanged" />
methods: {
onComponentChanged(e) {
console.log(e)
},
}
vue组合式开发、对比基础和组件开发(可以使用该方案,也可以作为参考)
uni-app
开发中,除了默认的开发模式,还支持 vue 的响应式开发
,下面主要介绍响应式开发的配置,以及常用的一些内容,也比较简洁,当然如果怕依赖太严重忘了原来的,也可以不用,都没问题的
ps
:用起来是真舒服
组合式发(响应式开发)
设置 setup 标签
script
标签后面加上 setup
,并去掉 export default
,这也是组合式开发第一步
js
<script setup>
//export default 去掉
</script>
了解在哪里导入我们需要的库
导入 uni-app
组件生命周期函数,组件生命周期在 @dcloudio/uni-app
库中
导入 vue
常用函数(后面会介绍),他们两个是分开的,响应式的一些 api
在 vue
库中,vue
组件生命周期的钩子也在里面,并且改了名字
js
import {
onMounted, //vue的 mounted 的钩子,改了名字,实际上推荐 uni-app的组件生命周期
reactive,
ref,
shallowReactive,
computed,
} from 'vue'
import { onLoad, onShow, onUnload} from '@dcloudio/uni-app'
生命周期钩子函数与普通函数的使用
需要注意的是,混合开发没有默认函数写到那个层级,他们都是在 script 中
的 同层函数
,和 import
一样
生命周期钩子函数
js
<script setup>
import {
onMounted, //vue的 mounted 的钩子,改了名字,实际上推荐 uni-app的组件生命周期
} from 'vue'
import { onLoad, onShow, onUnload} from '@dcloudio/uni-app'
onMounted(() => {
})
onLoad((options) => {
})
onShow(() => {
})
onUnload(() => {
})
</script>
普通函数
js
<script setup>
function onClickUpdateDesc() {
}
function onChanged(e) {
}
</script>
使用常用的响应式api
我们只要拼出来,就会自动导入该钩子(uni-app
的生命周期函数目前不会,要手动导入,也许以后会),如下所示
js
import {
ref,
reactive,
shallowReactive,
computed,
} from 'vue'
响应式 api 文档,可以参考 这里
下面只介绍比较常用的
ref
js
可以是这样对象的
const sTitle = ref('单个标题')
//也可以是这样对象的,内部更新也会即使响应到视图上
const title = ref({
title: '默认标题',
sub: {
subTitle: '子标题'
}
}) //这个也是
更改值的时候这样,需要 .value 形式更改,子对象改变,也会响应到视图上
js
sTitle.value = '初始化单个标题'
title.value.title = '初始化标题'
title.value.sub.subTitle = '初始化子标题'
使用时,则不需要 .value,会自动解包
js
<text>{{sTitle}} --- {{title.title}} -- {{title.sub.subTitle}}</text>
可以看到,其用起来 .value 是有点啰嗦的,后面的 reactive 将会深得你喜爱
reactive
创建对象,用它可以直接代替原来的 data
了,用起来也很舒服,并且可以分割成好几个对象,能对子对象解包,以便于修改时能应用到视图上
js
//使用上方便了
const data = reactive({
name: '哈哈',
age: 10,
stu: {
name: '一班',
number: 30,
},
})
更改内容,看着也简洁了,且子对象修改仍然可以反馈到视图上,和非响应式的 data
一样
js
data.name = 'mm'
data.age = 20
data.stu.name = '二班'
data.stu.number = 33
视图上就需要额外添加一个我们声明的 reactive
对象字段了,这里命名为 data
,多个对象甚至可以使用多个reactive
js
<text>名字:{{data.name}} ----- 年龄:{{data.age}}</text>
<text>班级:{{data.stu.name}} ------ 人数:{{data.stu.number}}</text>
shallowReactive
shallowReactive
为 reactive
的优化措施,但只有对象的第一层
会响应反馈到视图,子对象则不会响应到视图上,能提升一些性能,更需要注意别该出 bug
了
ps
:如果不存在性能瓶颈,就别瞎倒腾了,另外 ref 等也有 shallow 系列
js
//使用上方便了
const data = shallowReactive({
name: '哈哈',
age: 10,
stu: {
name: '一班',
number: 30,
},
})
同时修改对象和子对象,会发现子对象修改无法渲染出来,响应效率高了,是付出了些代价的,可以根据情况进行优化
js
data.name = 'mm'
data.age = 20
data.stu.name = '二班'
data.stu.number = 33
computed
这个 computed
计算属性,使用方式和默认的一样,只不过是利用了钩子函数罢了,如下所示
js
//相当于直接返回一个get方法
const averageAge = computed(() => (data.age + shadowData.age) / 2)
//带有set方法,修改该计算属性时,会根基自己的规则应用到指定对象上
const totolAge = computed({
get() {
return data.age + shadowData.age
},
set(newVal) {
let half = newVal / 2
data.age = half
shadowData.age = newVal - half
},
})
watch
至于 watch
、watchEffect
直接去看文档吧,感觉用的很少,就不多介绍了 -- 这里
简介一下 watch
使用
js
//第一个为观察属性,第二个为回调
watch(() => data.name, (val, preVal) => {
})
响应式的组件开发
创建组件的方式不多讲了,右键创建即可,应用和基础开发一样,只不过新增一个组件之间交互使用的 props、emit
罢了
这里面会用到的响应式 api
为 defineProps、defineEmits、reactive
defineProps
为声明属性 props的,为只读,方便接收参数,但不可以给默认值,通过 props.属性名
调用
defineEmits
为定义向外反馈通道的,会返回一个参数,通过返回的向外反馈
reactive
这个前面介绍过,是为了配合 props的,当我们需要更改 props 的某个参数时,可以将 props 的默认参数传递给我们需要的参数,然后内部使用即可,如果是依赖关系,那么最好使用 computed
js
<script setup>
import {
reactive,
} from "vue";
//也是只读的,defineProps 不需要从 vue 中引入
const props = defineProps({
name: String,
age: Number,
desc: String,
})
//定义一个向外反馈的 emit 函数指针,可以通过调用该函数直接反馈给外部
const emit = defineEmits(['onChanged'])
//这个可以用于在内部更新
const data = reactive({
cName: props.name,
cAge: props.age,
})
function onUpdateNameAge() {
//更改名字依旧
data.cName = '新名字'
data.cAge = 30
//调用函数反馈给外部即可
emit('onChanged', '更新了desc内容')
}
</script>
视图也比较简洁,可以使用 props
也可以使用 data
,根据自己要用的参数使用即可
js
<view @click="onUpdateNameAge">名字:{{data.cName}} 年龄:{{data.cAge}}</view>
<view class="normal-size black">备注:{{props.desc}}</view>
最后
如果只想在微信小程序或者支付宝小程序开发,那么无所谓了,如果考虑到可能会发布到其他平台,那么这个一定要学习练习一下,并且入门很快,希望大家都能有所收获
ps
:这篇文章可能你后续会有不少忘了,需要要查看回顾的,那么点赞收藏这篇文章,以后忘了看一下,保证屡试不爽😂