就是一个组件,我只想全局注册一次,不需要在需要用的页面再去引用,像vue里面app.vue的那种效果
- 发布:2019-05-08 18:58
- 更新:2024-01-31 15:27
- 阅读:39089
最佳回复
DCloud_UNI_OttoJi - 日常回复 uni-app/x 问题,如果艾特我没看到,请主动私信
久等了,我来看下这个问题,我看到评论中提到的一些解决方案有平台限制,我研究下,有进展我会更新到这里。
多端通用的 uniapp 怎么设置共用的组件
uniapp 怎么设置所有页面共用的组件
https://ask.dcloud.net.cn/question/70510
我看了评论区各位的反馈,有的讨论已经大大拓展了最初的问题,也有热情的社区用户贡献了技术方案,特别感谢他们,为他们点赞。
很多人争论的点,是使用场景不同,小程序、app 环境会有一些限制,不能直接使用浏览器 h5 的方案,这样导致了一些用户评论的误解。我整理下不同的业务场景,供不同需求的人使用。下面场景始终考虑多端。
前置共识:
- 在小程序运行环境和 h5 不同,没有 document 方法,也就不能创建元素、插入元素。
- 小程序环境中,彼此页面独立
- uni-app 在 vue2 中使用 webpack 工具,在 vue3 中使用 vite 工具。
场景 1: 最简单的组件复用
无论是 h5、小程序、app 都遵循 vue 的写法,引入组件 - 使用组件。
也就是组件需要先引用注册,再去使用。在 vue2/vue3 中引入组件都一致。
场景 2:组件不想每次都 import 引入
组件每次都需要 import,推荐使用 easycom 功能。
easycom 是 HBuiderX 2.5.5 可用的功能,早期的讨论可能没注意到
使用 easycom 自动注册方案,使用 uni-app
提供的功能特性,自动按照规则自动匹配,直接使用
https://uniapp.dcloud.net.cn/collocation/pages.html#easycom
省去了导入的方案,效果和场景 1 一样,正常使用组件。
场景 3:想自定义实现 uni.showToast
uni-app 内置的 uni-showToast 可以通过函数调用实现消息弹窗,这个在小程序端是依赖小程序本身提供的功能做的包装。比如微信小程序提供了 wx.showToast
方法。
有的业务想拓展功能、更改样式,符合自己的业务逻辑。比如评论里提到的全局剪切板弹窗、全局悬浮球等。在 web/app 中很容易实现,但在小程序端不能实现,因为小程序本身不支持动态创建。那要怎么做呢?看看小程序组件库就知道了。
在小程序组件库中,为了解决这个场景,一般需要在 template 里使用组件,在逻辑中控制组件显隐,说到底是要保证弹窗里的元素在页面中存在,等待唤起生效。
伪代码如下:
<xx-popup show="{{ show }}" bind:close="onClose">内容</xx-popup>
如果不想在模版中声明组件,可以考虑在编译时候自动填充内容。举例子,比如用户这样伪代码:
<template>
<view>123</view>
</template>
通过编译器插件编译时候追加元素。
<template>
<my-toast ref='mytoast' />
<view>123</view>
</template>
也就是说,这个组件声明是必须存在的,只是由谁来完成。
在 uni-app 的工具链中,使用了 webpack/vite,社区热心的用户已经开发了对应的插件功能。
比如:
- webpack 方案
vue-inset-loader
,核心思路是调整 webpack 配置使用 loader,对文件进行中间处理。文档地址 https://ask.dcloud.net.cn/article/39345 仓库地址 https://github.com/1977474741/vue-inset-loader - vite 插件方案
vue3-inset-loader
,和上面思路一致,vite 方向的插件,仓库地址 https://github.com/smartXJ/vue3-inset-loader/tree/main
两个方案,都使用了相同的配置,不需要额外学习配置方法。由衷感谢社区的共享方案,大家有时间可以给点点 github star。
场景 4:想实现 app.vue 的效果
这里讨论比较多,用户想和 web 一样,对 app.vue 进行修改,实现一劳永逸的效果。如果考虑多端实现,就不能这样做。因为 app.vue 在小程序端不参与页面渲染。app.vue 地址
技术实现思路是,使用一个自定义组件放在页面顶部,通过插槽 slot 编写具体的页面逻辑,可以实现整体页面的包装。这种方案比较直观,同样可以实现场景 3 的需求。
<template>
<my-page>
<view>123</view>
</my-page>
</template>
这里推荐社区热心用户 自学的烦恼,提供的方案 https://ext.dcloud.net.cn/plugin?id=2560
总结
可以看到,最终还是因为平台限制不能想 web 一样灵活,产生了各种变通方案。
如果上面提到的场景,还不能满足你的需求和使用场景,你可以提供你的发行方案,描述使用场景反馈给我。
-
这个可以解决返回页面失效问题,代码有点复杂 可以适当理解一下 大致逻辑就是在全局定义的时候是注册在当前页面下而不是全局,调用的时候根据当前页面进行查找返回,这样其实每一个页面的show方法其实都在$w下
import Vue from 'vue'
export const name = 'gobalComponents'
// 配置全局组件,保证全局组件在返回页面时依旧可以使用
const get = (name) => {
let $w = Vue.prototype.$w
const page = uni.$u.page()
return $w?.gobalComponents[`${page}`][`${name}`]
}
const add = (name, fn) => {
let $w = Vue.prototype.$w
const page = uni.$u.page()
const addObj = ($w?.gobalComponents && $w?.gobalComponents[`${page}`]) ?
$w.gobalComponents[`${page}`] : {}
addObj[`${name}`] = fn
$w.gobalComponents = {
...$w.gobalComponents,
[`${page}`]: addObj
}
Vue.prototype.$w = {
...$w,
get [`${name}`]() {
return get(name)
}
}
}
export default {
add,
get
}
2022-09-03 22:00
-
回复 w***@126.com: 这里有一个小问题,由于用的是拓展运算符,所有如果又多个全局组件,最后一个会把前面的覆盖掉(也不算是覆盖 就是会让前面的get失效),后来考虑使用Proxy统一写一个get函数进行处理就ok了
2022-09-03 23:07
hhyang - 如有问题,请添加QQ1606726660 备注付费咨询
-
回复 hhyang: 他的意思是每个页面都要引入那个组件的插槽,他想要页面不写插槽,统一引入,所有页面公用,比如100个页面我要写100个插槽,但我就只想写一次
2021-02-22 17:17
-
回复 hhyang: 这么简单的问题都没有听懂,他的意思就是不用每个页面都有代码,在全局文件引入就行了,看你也不聪明到哪里去,一遇到这种问题,不理解就说这么极端的话,看不起人的最让人看不起。鄙视你这种回答问题的方式。自己250,别把所有人想成250
2021-04-10 14:41
-
回复 v***@163.com: 我也有这个需求,已经差不多快成熟的产品,现在要追加一个全局功能,要是每个页面再去加组件感觉不太好,而且万一以后还要加其他的就更麻烦了,不知道有解决办法没有
2021-12-23 10:44
楼主说的应该是Vue中app.vue文件里写的html内容吧?
是不是例如
<template>
<div id="app">
<router-view/>
<my-component></my-component>
</div>
</template>
中的my-component?
是的话我也想问这个。
否则页面多到十几或者几十个的话,每个页面都要去写一遍,太麻烦了。
现在uniapp里的app.vue没有html部分...
尹成诺 - 辣鸡前端
我也遇到了,不过也算是解决了。这里是思路:
https://ext.dcloud.net.cn/plugin?id=1294
vue-template-compiler 还能这么用
跨端通用参考方案:
- 新建一个 base-page.vue 文件作为页面根组件,其中引入公共组件,并暴露操作方法 showPopup。
- 新建一个 base-page.js 文件作为页面 mixin 引入根组件并暴露根组件操作方法 showPopup。
- 每个页面引入 base-page.js 并加入 mixins 中,根节点使用 base-page 组件。
- 页面或者组件中调用 this.$root.showPopup()。
扩展阅读:
- 具体实现可以参考其他 自学的烦恼 写的示例:https://ext.dcloud.net.cn/plugin?id=2560
- 其中重复的工作在步骤3,如想省略步骤3,可以尝试自行调整编译器,自动插入到每个页面。
app平台,可以通过创建一个透明的页面A,将弹窗视图放到A页面上,显示弹窗就navigateto到A页面,具体实现可以参照这个示例 https://ext.dcloud.net.cn/plugin?id=6644
神的尾巴 - 欢迎关注我的微信公众号:神的尾巴
我提供一种我目前的解决思路:
前面回答里面说的在App.vue里面,添加template,在APP实测无效
目前我有一个通用的page组件,用来处理作为所有页面的父组件,处理loading、骨架图等,在该父组件添加全局组件
获取ref,有两个方案:
- 在page组件添加方法getRef(),获取page组件内的ref
- 初始化的时候注册到vuex,在使用的时候到vuex中取
两种方案都能获取到,看你怎么使用方便,我是使用的方案2,然后在通用mixins中添加获取全局组件的方法
-
回复 s***@aliyun.com:
<template>
<view>
<router-view/>
<!-- 你的全局popup组件,在渲染成功后,没执行组件的mounted -->
<popup />
</view>
</template>2020-06-18 22:48
-
"目前我有一个通用的page组件,用来处理作为所有页面的父组件,处理loading、骨架图等,在该父组件添加全局组件",这句话不太明白,能多说点嘛?谢谢~
2020-07-16 10:33
简单得很,在components下创建组件目录,命名跟组件文件一致,然后把该组件放到对应的目录下,就可以直接在页面中使用了,不需要引入。同理,有多少个组件就创建多少个目录,记住:目录命名一定要跟组件命名一致
以下在App.vue中修改 h5可以正常使用,其他平台没有试过,而且App.vue中不能写v-model,只能用:value代替
<template>
<view>
<router-view />
<u-popup :value="true">哈哈</u-popup>
</view>
</template>
<script>
import uPopup from "@/uview-ui/components/u-popup/u-popup.vue";
export default {
components: {
'u-popup': uPopup
},
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show');
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style lang="scss">
@import "uview-ui/index.scss";
</style>
借鉴 > https://ext.dcloud.net.cn/plugin?id=2560 也就这样比较好了。的方法
在App.vue中引用全局组件
App.vue代码如下:
<template>
<globe-page></globe-page>
</template>
<script>
import globePage from "@/components/globe-page.vue";
export default {
components: {
'globe-page': globePage
},
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show');
},
onHide: function() {
console.log('App Hide')
}
}
</script>
globe-page.vue代码如下:
<template>
<view>
<router-view />
<u-popup ref="popup" v-model="show">哈哈</u-popup>
</view>
</template>
<script>
import uPopup from "@/uview-ui/components/u-popup/u-popup.vue";
export default {
components: {
'u-popup': uPopup
},
name:"globe-page",
data() {
return {
show: false
};
}
}
</script>
<style>
</style>
关于如何在App.vue 的中onShow中改变 globe-page.vue中的 show,有多种方法可以实现,这里就不说了。
兄弟们,可以参考,这个,全平台可用
-
大佬,按这个方法修改后会报错,无法正常编译到小程序,不知道哪里有问题,具体错误如下:
[HBuilder] 19:02:12.579 ERROR Error: EINVAL: invalid argument, mkdir 'E:\uniAppProject\MyTest\unpackage\dist\build\mp-weixin\E:\uniAppProject\MyTest\components\test'
[HBuilder] 19:02:12.579 Error: EINVAL: invalid argument, mkdir 'E:\uniAppProject\MyTest\unpackage\dist\build\mp-weixin\E:\uniAppProject\MyTest\components\test'2023-07-18 19:06
董路飞 - 搜索小程序麻丝和 App 麻丝
此贴发布:【2019-05-08 18:58】
现在这个时间 【2023/08/28】,
只需要在根目录创建components文件夹,里面写要复用的组件,然后其他页面就可以直接使用这个组件了(不需要在项目配置文件里写配置,也不需要在页面文件引入此组件)
这不就相当于公共组件?
1***@qq.com
希望能支持小程序,app(vue,nvue) 这些页面,谢谢
2024-01-30 11:16
DCloud_UNI_OttoJi
回复 1***@qq.com: 请看下我楼上的回复,是否满足你的要求,解答你的疑问。如果不能,请补充你的具体使用场景。
2024-01-31 15:30
1***@qq.com
回复 DCloud_UNI_OttoJi: 之前开发的 app 场景就是之前页面开发太多了,逻辑比较多,不想全部改动变成插槽的形式,有没有其他方式实现呢
2024-04-12 17:22