easycom组件模式是怎么回事
官方文档:https://uniapp.dcloud.io/collocation/pages?id=easycom
easycom组件就是符合components/组件名称/组件名称.vue
目录结构的组件。
简单说,只要听从官方的约定,那么无需引入、无需注册,可以实现开发时全局使用、打包时按需打包。
注意事项:
官方文档说的注意事项我就不重复了。
小程序原生组件要放到
/wxcomponents/
里面,并不是放到components
里面,也不适用easycom。符合
components/组件名称/组件名称.vue
目录结构,只要存放,无需其他任何操作就会被HBuilderX认出,但现实中几乎没人这么存,因为我们可能要使用多个组件库,这时候怎么办?你可以到pages.json去明确注册一下,这样存放路径就不那么受限了。例如:
// pages.json
{
"easycom": {
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
},
// 以下为pages.json本身已有的内容
"pages": [
// ......
]
}
我们就看这行,它其实类似于正则替换,以u-
开头的组件名,都会自动去@/uview-ui/components
里面找。
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
如果还有一个组件库也是以u-
开头作为组件名呢?怎么解决冲突?
首先看哪个组件库是低使用频率的,然后pages.json注册它的时候,不要写^u-(.*)
,改成别的前缀,比如^ux-(.*)
,使用的时候也注意要使用这个前缀就行了,比如<ux-button></ux-button>
。
vue语法 this.$emit('update:xxx') 在小程序不生效?
似乎就是不生效,可以用另外的写法:
this.$emit('update:fieldValue', e.detail.value);
// 改成:
this.$emit('update', e.detail.value);
其中fieldValue
是prop名,由于父组件里要显式声明自定义事件,所以改成省略。
然后,父组件里需要显式声明自定义事件:
// 给组件加上
@update="password=$event"
页面间传递数据、调用方法的几种方式
URL传参
就不说了。
向navigateTo的页面传递数据、调用方法
这个是小程序的基础知识,在此简单说一下。比如,我想调用后一个页面的xxxToast方法,做法是:
A页面:
methods: {
onTap() {
uni.navigateTo({
url: '/pages/mine/index',
success: (res) => {
res.eventChannel.emit('xxxToast', { title: 'TOAST的标题' });
}
})
}
}
mine页面:
onLoad() {
const eventChannel = this.getOpenerEventChannel();
eventChannel.on('xxxToast', ({title}) => {
uni.showToast({
title
})
}),
},
向navigateBack的前一页传递信息
有这样一个场景,从文章列表页打开某个详情页,详情页有个删除按钮,点击删除,则文章被删除,并跳回列表页,列表页应重新ajax,或者从内存中的列表数组中删掉该文章。让列表页更新数据不允许无脑更新,必须是有指令才更新,没指令则不更新。我们分析一下:
似乎需要用navigateBack,但是navigateBack的
success
不具有res.eventChannel
能力。navigateBack没有
url
属性,无法URL传参。换用navigateTo的话,被删除的详情页会留存在页面栈,手机回退会重新进入被删除的详情页,肯定不允许。
换用redirectTo的话,虽然详情页被杀掉,因此不会重新进入详情页,但是进入列表页之后,手机回退会又进一次列表页,也不允许。
所以,我们依然需要用navigateBack,然后用某种方式传递信息,怎么办呢?
可以利用getCurrentPages()获取页面栈,然后执行前一页的方法即可。
A页面:
methods: {
list() {
// ...
}
}
mine页面(也就是B页面):
原理是利用页面栈调用其他页面的方法。但不同平台又有区别。
H5和小程序必须先调用页面栈的方法,再回退,也就导致,页面栈要找倒数第二个页面。
APP可以有2个选择,那么采用上方的方法,要么是先回退,再调用页面栈的方法。
综合说,应当全平台统一采用先调页面栈、后回退的方式。
然后区分.$vm
。
methods: {
onTap() {
let pages = getCurrentPages();
let prevPage = pages[pages.length - 2];
// #ifdef H5
prevPage.list();
// #endif
// #ifndef H5
prevPage.$vm.list();
// #endif
uni.navigateBack()
}
}
A页面调用uni原生方法,B页面显示
现在,我们不跨页调用自定义方法,只是调用uni原生方法, 这时候最简单,直接写到success就行了。适用于所有路由方法。不适用于H5,因为H5一旦路由变化就终止一切后续代码。
uni.navigateBack({
success: () => {
uni.showToast({
title: '哈哈哈'
})
}
});
引用本地图片作为背景图
本地背景图片的引用路径推荐使用以~@
开头的绝对路径。
动态添加右上角按钮
// #ifdef APP-PLUS
var wv = plus.webview.currentWebview();
wv.setStyle({
titleNView: {
titleText: '删除'
}
});
// #endif
同样的,plus.webview.currentWebview()
可以做很多事,参看:
https://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewObject
引入Vant组件报postcss-loader错的解决办法
如果引入Vant Weapp来开发小程序,不会有报错,但是如果同时发布到H5,就会报错“postcss-loader”相关错误,这个问题解决起来其实很简单,关键是看你知不知道。
打开@vant/weapp/icon/index.wxss
,前几行是:
@import '../common/index.wxss';@font-face{font-weight:400;font-family:vant-icon;font-style:normal;font-display:auto;src:url(https://img.yzcdn.cn/vant/vant-icon-96970a.woff2) format("woff2"),url(https://img.yzcdn.cn/vant/vant-icon-96970a.woff) format("woff"),url(https://img.yzcdn.cn/vant/vant-icon-96970a.ttf) format("truetype")}
在里面找format("woff2"),url
和format("woff"),url
,问题就出在这了。
给每个url
前面敲一个空格,保存。重新编译,故障解除!
但是,这种跨端发布的操作,不一定永远能成功,因为Vant开发者没打算让你跨端使用。
同样,在H5开发中引入Vant 2,也会报同样的错误,也可用这种方法解决。如果你把vant 2安装在了node_modules里,无妨,把/lib/index.css拷出来,修改,引用这个css就行了。
解决APP环境没有navigator变量的问题
H5组件库往往使用navigator来判断浏览器是安卓还是iOS环境,以便做出不同的兼容,但是APP平台根本没有这个变量,组件库直接报错。怎么办?我们创建一个顶级navigator就可以了。
if (!window) {
global.navigator = {
userAgent: plus.navigator.getUserAgent()
}
}
其中global
相当于window
,plus.navigator.getUserAgent()
是H5 plus提供的API。