likes
comments
collection
share

uni-app介绍

作者站长头像
站长
· 阅读数 41

前言

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

psuni-ui 是因为避免了基本ui组件导入,且能给我们后续组件使用编写带来便利,非常方便;另外,新项目能使用vue3,最好使用vue3,毕竟据说性能有提升

uni-app介绍

创建完后,应该长成下面这样子(package.json是后面添加的,后面再说)

uni-app介绍

我们可以看到 uni-modules 特色的组件,其默认开启easycom模式,在这里面,不引用,可以直接使用,且没有使用到的组件也不会被打包进去,力推

uni-app介绍

接下来配置 manifest.json,其中 uni-app 应用标识,需要到 uni-app平台申请,没有点击获取注册就可以了,跟其他平台一样,不多介绍

uni-app介绍

上面的基础配置配置完毕后,就根据我们的平台配置就可以了,下面以微信小程序为例,进行简单配置(不配置调试不了哈)

uni-app介绍

就这样我们的项目就算初步建成了

文件相关简介与部分配置

文件相关我们主要介绍下面这些,一些后面会在基础开发和组件等展开介绍

uni-app介绍

pages

文件夹是开发页面的目录,有xml、script、css等,在同一个页面

uni-app介绍

static

为静态资源路径(图片、字体等)

uni-app介绍

uni_modules

为符合uni_modules规范的组件文件夹,后面会具体介绍(无论是三方还是自定义组件这里都很重要,主要是方便简洁),然后是其他的,下面一个一个简单介绍

ps:其中 my-component是我创建的属于自己项目的组件,后续会介绍,其他的是创建项目时带入的

uni-app介绍

manifest.json

其就是基础配置用的,用于配置 uni-app 或者一些平台调试打包的参数,很简单不多介绍

page.json

配置导航路由、组件、tabbar、easycom等组件相关参数的如下所示,一目了然,自己创建完毕后就知道咋回事了(后面还会稍微详细点介绍),如下图所示

uni-app介绍

App.vue

为我们实际解除项目的开始(实际上更早的应该在main),这是进入小程序后会走的几个方法,很实用(onLaunch这个属于应用启动时走的,正常页面用的onLoad,详细可以看后面的生命周期)

uni-app介绍

ps:细心的可能注意到 stylelang='scss',其就是设置 scss 模式的,当然也可以支持less,基础的 css 更没问题了

uni.scss

为系统给我们提供的全局样式文件,和 css、less 类似,其和less一样可以很方便的定义全局css变量、选择器等,且不引用可以直接在xml中使用,与定义在 App.vue中的style样式一样,可以全局使用,和微信小程序类似

uni-app介绍

package.json、node_modules

是前端开发基本都会用到的,通过 package.json 配置,使用 npm、yarn 引入三方到 node_modules文件夹,这个后面引入组件和 easycom配置再详细介绍

全局参数相关配置

全局配置,实际上上面介绍的都差不多了,这里面再详细介绍一下

uni.scss 为系统给我们预留的一个全局样式文件,且为 scss 模式,因此支持很方便的全局变量定义,选择器使用,甚至嵌套都有可能(但不建议全局嵌套,可读性差),我们只需要加入一些常用属性、选择器样式即可

App.vue则是我们实际接触开发的第一个vue文件了,和小程序系列开发类似,在script中,我们可以定义一些全局变量,更加方便我们使用,同时,scss 样式中,我们也可以像创建一些全局 scss变量、选择器等,需要用到另外一些 scss 文件,也可以 @import 的方式导入即可(例如:我们有一些组件的公用样式,可以导入)

uni-app介绍

组件生命周期与注意项

小程序组件生命周期和vue组件生命周期不同,uni-app主要开发小程序,因此首推小程序的生命周期(小程序运行时,vue的一些生命周期是不会走的,这点可以自行尝试)

小程序生命周期入口vue生命周期入口

小程序常用生命周期(推荐),vue的生命周期就不多介绍了,要用可以参考上面入口,用的比较多的就是 mounted、unmounted了,其他的有时候不会调用哈

uni-app介绍

<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:起名最好跟系统一样使用,不采用驼峰和蛇形,使用 - 作为单词目录的间隔

uni-app介绍

创建好了之后,如下所示,xml、js、css开发位置一目了然,然后在里面开发吧

ps:由于都在一个页面,所以代码长一些没办法的事情,可以使用组件 + 抽离公共组件 + 抽离业务等方式来缩减单文件代码

uni-app介绍

tabbar

tabbar 在我们前面介绍的 pages.json 文件中

//到这里相信不需要我过多介绍了吧
"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": "我的"
    }]
},

绑定参数、绑定事件

静态绑定 直接传入内容即可,无论是字符串还是数字等

<image src="@/static/c1.png"></image>

动态绑定参数 只需要在属性前面加入 : 即可完成绑定,外部属性变化会传递到组件内部,以完成更新

绑定事件只需要加入 @ 即可,内部的事件会反馈给外面指定方法,即算绑定成功

如下所示

<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>

资源路径

资源路径的引用主要以 绝对路径、相对路径的方式来引入

//绝对路径,通过根目录下的某个文件夹开始直接引入
<image src="@/static/c1.png"></image>

//相对于当前文件位置引入文件(用的最舒服的就是组件同级目录下,引用自己的图片、代码逻辑文件等)
<image src="../../static/c2.png"></image>

显示字符参数

与上面不同的是,显示字符不需要绑定之类的,只需要直接填充即可,如果需要显示或者嵌入某个字符串,可以使用双大括号方式引入变量,即: {{ 变量 }},这个跟微信小程序一样的

<text>总年龄:{{totolAge}}</text>
<text>{{totolAge}}</text>

v-if、v-else-if、v-else、

主要是一个判断语句

<view v-if="status===1">我成功了</view>
<view v-else-if="status===2">我失败了</view>
<view v-else>我都没参加</view>

注意:不建议跟 v-for 同时使用,vue2v-for优先级高,vue3v-if优先级高

v-for

常见的遍历语句,可以生成 list,另外如果需要提高性能,需要设置:key,可以加入唯一值,也可以直接使用索引,能避免更新时频繁创建 item

<view v-for="(item, index) in listData" :key="index">
    <text>第{{index + 1}}个元素是:{{item}}</text>
</view>

css支持配置(scss、less)

只需要设置 stylelang 属性即可,需要支持 scss 就设置成 scss,需要支持 less 就设置成 less 即可,当然也可以设置成 css, 非常方便,这里就不多介绍了,需要学习前两个的可以搜一下

<!-- 设置 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 内容 和显示内容

<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 来解决,computeddata 字段同级

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 很舒服地替代,且一般在组件开发用的多

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

methodsdata 同级,我们平时写的自定义函数都是在这里面(处理系统的生命周期函数,还有上面的一些固定声明),包括我们的监听回调等基本都在这里编写

<script>
    export default {
        data() {
            return {
                name: '哈哈',
            };
        },
        methods: {
            onLogin() {

            },
        }
    }
</script>

javascript抽离逻辑文件并导入(import)

UI组件我们可以以组件方式抽离,但复杂的业务往往是万恶之源

当我们主模块业务较多时,可以抽离出来一份业务逻辑,并将其抽离到合适位置(私用在page同名文件夹下即可,公用可以另起一个全局公用文件夹即可)

如下所示,抽离出代码,右键点击新建,创建vue文件(注意不是页面,页面会在pages.json创建目录)

uni-app介绍

然后只留下 script 标签即可,在 export default 里面创建暴露方法即可

uni-app介绍

//在使用的script中导入
import smallF from './small-function.vue'

//调用即可
smallF.getOtherInfo()

css导入 import

@import '@/uni_modules/uni-scss/index.scss';

设置单个页面背景大小

全局 page 类似,只需要在单个页面 page 设置即可

---单个页面的css---
//设置单个页面背景,添加css选择器
page {
    width: 100%;
    height: 100%; //这样页面就会被拉伸满了,注意滚动视图一般不这么推荐,否则可能会出现滑动障碍
}

设置导航和单个页面下拉刷新功能

//全局样式
"globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "uni-app",
    "navigationBarBackgroundColor": "#F8F8F8",
    "backgroundColor": "#F8F8F8",
    "app-plus": {
        "background": "#efeff4"
    }
}

uni-app介绍

onPullDownRefresh() {
    setTimeout(function() {
        //不能一直刷新到最长时间,成功过后,注意调用方法立即停止下拉刷新动画
        uni.stopPullDownRefresh()
    }, 500)
},

全局样式(导航、状态栏、标题、窗口背景色)

用于设置应用的状态栏、导航条、标题、窗口背景色 -- 入口

//常用的就下面几个了
"globalStyle": {
    "navigationBarTextStyle": "black", //导航文字颜色
    "navigationBarTitleText": "uni-app", //导航默认标题
    "navigationBarBackgroundColor": "#F8F8F8", //导航背景颜色
    "backgroundColor": "#F8F8F8", //下拉出来的背景颜色
}

uni-app介绍

导航、传值、页面栈

导航

其中用的最多的就是uni.navigateTo、uni.redirectTo、uni.reLaunch、uni.switchTab、uni.navigateBack了 --- 入口

uni.navigateTo:跳转到某一个页面

uni.navigateTo({
    url: '/pages/login/login'
})

uni.redirectTo:关闭当前页面,跳转到应用内的某个页面

//假设想从 help1 跳转到 help2,类似的,为了避免打开过多页面,可以替换页面
uni.redirectTo({
    url: '/pages/help/help2'
});

uni.reLaunch:关闭所有页面,打开到应用内的某个页面,能减少页面栈,常用于启动页到其他页面

uni.switchTab:跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面

uni.navigateBack:返回到页面栈上一个页面,其中有一个 delta 参数,可以控制返回的页面数,有时配合页面栈用起来会更舒服

传值

这里介绍就以 navigateTo 为例,其他的有的不支持有的类似

方式一: 以 url 方式传递,快捷方便,缺陷也很明显,不支持回调,且数据长度很短,一些甚至只限制了几十个字符,一般传递个 id 就足够了

//跳转
onLogin() {  
    let name = 'marshal'
    uni.navigateTo({
        url: `/pages/login/login?name=${name}` //长度受限不推荐
    })
}

//跳转的页面,在onLoad 的参数中可以获取到 url 中的参数
onLoad(options) {
    console.log('拼接url传递的会在这里作为参数显示,适合短字段', options)
}

方式二:使用 eventChannel 传递(和微信小程序一模一样),支持传递大对象,支持回调

//跳转
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)
    })
}

页面栈

当我们导航的时候会存在一个页面栈,用来保存或者恢复之前某一个页面使用的,因此了解其可以帮助我们返回到指定的页面,或者是做到特殊的功能

//获取当前页面栈
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)

触发全局的自定义事件。附加参数都会传给监听器回调

uni.$emit('update', '页面更新了')

uni.$on(eventName,callback)

uni.$on('update',function(data){
    console.log('data');
})

uni.$off([eventName, callback])

移除全局自定义事件监听器

uni.$off('update')

uni.$once(eventName,callback)

监听全局的自定义事件,和 $on 类似,事件可以由 uni.$emit 触发,但是只触发一次,在第一次触发之后移除监听器。

getCurrentPages、selectorQuery简介

getCurrentPages:获取页面栈数组,可以获取顶层或者下层页面对象(可以通过 page.route 获取页面path,用于判断)

selectorQuery:获取 page 某个页面节点,通过该方法定位页面,可以锁定某个页面内的某个组件

因此,他们两个搭配,可以获取到某个 page 页面内的某个组件,然后给该组件动态赋值或者添加回调,不可谓不爽,一般用于方便弹窗弹窗弹出

--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 开始)

uni-app介绍

扩展组件开发(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 目录即可,并告诉那人别瞎搞😂)

uni-app介绍

上面我们创建了自己的组件插件,我们默认有一个同名组件,我们要不要都行,然后在创建一个我们自己的组件

uni-app介绍

外面调用也是直接使用即可,例如我们在主页调用它

uni-app介绍

npm导入和自建组件的配置方式

我们可以随意搭配使用,建议使用 dcloud 市场组件,还有自建组件,npm 非必要不使用,一些不太符合规范的使用起来相对比较麻烦

npm 方式导入

npm 导入,假如以前是开发 vue 的,对于vue 的一些组件很喜欢,也可以通过 npm 方式导入使用,不过前提是它支持 easycom 的形式,不然很麻烦(需要一个一个导入,因此这里不教其他方式怎么引入的,参考 这里,反正不好用到我都懒得看🤣)

没有过 npm 的这里不介绍了,其他地方可以看,一顿操作后,我们导入了一个库,他的目录是下面这样的

uni-app介绍

除了 uni_modules 目录,其他的默认都不会扫描,因此需要我们自己配置,然后我们进入到 pages.json 文件中,通过 easycom 给我们的高效扫描模式,批量配置即可

如下所示,我们在 pages页面路径同级下,粘贴如下代码,更改目录定位匹配到我们使用的组件即可,参考上面目录即可理解

// 例如: 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 添加新的配置项即可,其实一看还挺简单的,参考下面,直接改一个前缀名就可以了哈

uni-app介绍

"easycom": {
    "autoscan": true,
    "custom": {
        // 匹配自检的components里面的组件,my-为前缀
        "^my-(.*)": "@/component/my-$1/my-$1.vue" 
    }
},

组件的使用和注意事项

接收属性 props,在 data 的同级声明 props, 一般我们都是直接设置默认值,或者什么都不设置

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

data() {
    //如果想更新值,在这里获取即可
    return {
        CAge: this.age,
        cName: this.name,
    }
},

对完传递属性,就想我们使用 view@click 一样,我们需要这么做,在 data 的同级声明 emits,对外暴露

//对外传递的事件名称
emits:['valueChanged'],

使用时传递事件名称 + 传递反馈对象参数即可

this.$emit('valueChanged', this.CAge)

外部调用组件时,这样即可正常使用了

<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,这也是组合式开发第一步

<script setup>
    //export default 去掉
</script>

了解在哪里导入我们需要的库

导入 uni-app 组件生命周期函数,组件生命周期在 @dcloudio/uni-app 库中

导入 vue 常用函数(后面会介绍),他们两个是分开的,响应式的一些 apivue 库中,vue 组件生命周期的钩子也在里面,并且改了名字

import {
    onMounted, //vue的 mounted 的钩子,改了名字,实际上推荐 uni-app的组件生命周期
    reactive,
    ref,
    shallowReactive,
    computed,
} from 'vue'

import { onLoad, onShow, onUnload} from '@dcloudio/uni-app'

生命周期钩子函数与普通函数的使用

需要注意的是,混合开发没有默认函数写到那个层级,他们都是在 script 中同层函数,和 import 一样

生命周期钩子函数

<script setup>
    import {
        onMounted, //vue的 mounted 的钩子,改了名字,实际上推荐 uni-app的组件生命周期
    } from 'vue'
    import { onLoad, onShow, onUnload} from '@dcloudio/uni-app'
    
    onMounted(() => {
        
    })

    onLoad((options) => {
    
    })

    onShow(() => {

    })

    onUnload(() => {
        
    })
</script>

普通函数

<script setup>
    function onClickUpdateDesc() {
        
    }

    function onChanged(e) {
        
    }
</script>

使用常用的响应式api

我们只要拼出来,就会自动导入该钩子(uni-app 的生命周期函数目前不会,要手动导入,也许以后会),如下所示

import {
    ref,
    reactive,
    shallowReactive,
    computed,
} from 'vue'

响应式 api 文档,可以参考 这里

下面只介绍比较常用的

ref
可以是这样对象的
const sTitle = ref('单个标题')

//也可以是这样对象的,内部更新也会即使响应到视图上
const title = ref({
    title: '默认标题',
    sub: {
        subTitle: '子标题'
    }
}) //这个也是

更改值的时候这样,需要 .value 形式更改,子对象改变,也会响应到视图上

sTitle.value = '初始化单个标题'

title.value.title = '初始化标题'
title.value.sub.subTitle = '初始化子标题'

使用时,则不需要 .value,会自动解包

<text>{{sTitle}} --- {{title.title}} -- {{title.sub.subTitle}}</text>

可以看到,其用起来 .value 是有点啰嗦的,后面的 reactive 将会深得你喜爱

reactive

创建对象,用它可以直接代替原来的 data了,用起来也很舒服,并且可以分割成好几个对象,能对子对象解包,以便于修改时能应用到视图上

//使用上方便了
const data = reactive({
    name: '哈哈',
    age: 10,
    stu: {
        name: '一班',
        number: 30,
    },
})

更改内容,看着也简洁了,且子对象修改仍然可以反馈到视图上,和非响应式的 data 一样

data.name = 'mm'
data.age = 20
data.stu.name = '二班'
data.stu.number = 33

视图上就需要额外添加一个我们声明的 reactive 对象字段了,这里命名为 data,多个对象甚至可以使用多个reactive

<text>名字:{{data.name}} ----- 年龄:{{data.age}}</text>
<text>班级:{{data.stu.name}} ------ 人数:{{data.stu.number}}</text>
shallowReactive

shallowReactivereactive 的优化措施,但只有对象的第一层会响应反馈到视图,子对象则不会响应到视图上,能提升一些性能,更需要注意别该出 bug

ps:如果不存在性能瓶颈,就别瞎倒腾了,另外 ref 等也有 shallow 系列

//使用上方便了
const data = shallowReactive({
    name: '哈哈',
    age: 10,
    stu: {
        name: '一班',
        number: 30,
    },
})

同时修改对象和子对象,会发现子对象修改无法渲染出来,响应效率高了,是付出了些代价的,可以根据情况进行优化

data.name = 'mm'
data.age = 20
data.stu.name = '二班'
data.stu.number = 33
computed

这个 computed 计算属性,使用方式和默认的一样,只不过是利用了钩子函数罢了,如下所示

//相当于直接返回一个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

至于 watchwatchEffect 直接去看文档吧,感觉用的很少,就不多介绍了 -- 这里

简介一下 watch 使用

//第一个为观察属性,第二个为回调
watch(() => data.name, (val, preVal) => {

})

响应式的组件开发

创建组件的方式不多讲了,右键创建即可,应用和基础开发一样,只不过新增一个组件之间交互使用的 props、emit罢了

这里面会用到的响应式 apidefineProps、defineEmits、reactive

defineProps为声明属性 props的,为只读,方便接收参数,但不可以给默认值,通过 props.属性名 调用

defineEmits为定义向外反馈通道的,会返回一个参数,通过返回的向外反馈

reactive 这个前面介绍过,是为了配合 props的,当我们需要更改 props 的某个参数时,可以将 props 的默认参数传递给我们需要的参数,然后内部使用即可,如果是依赖关系,那么最好使用 computed

<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,根据自己要用的参数使用即可

<view @click="onUpdateNameAge">名字:{{data.cName}} 年龄:{{data.cAge}}</view>
<view class="normal-size black">备注:{{props.desc}}</view>

最后

如果只想在微信小程序或者支付宝小程序开发,那么无所谓了,如果考虑到可能会发布到其他平台,那么这个一定要学习练习一下,并且入门很快,希望大家都能有所收获

ps:这篇文章可能你后续会有不少忘了,需要要查看回顾的,那么点赞收藏这篇文章,以后忘了看一下,保证屡试不爽😂