群UI需要调整

This commit is contained in:
cbb
2026-01-23 16:55:42 +08:00
parent 99396e9966
commit c508b1fcb4
21 changed files with 1069 additions and 211 deletions

View File

@@ -287,6 +287,7 @@
}
function onCurrentConversationUpdate(conversation: IConversationModel) {
updateUIUserNotInGroup(conversation)
// return when currentConversation is null
if (!conversation) {

View File

@@ -27,12 +27,12 @@
</div>
</div>
<div class="tui-contact-list-card-right">
<div
<!-- <div
v-if="groupTypeForShow"
class="tui-contact-list-card-right-group-type"
>
{{ groupTypeForShow }}
</div>
</div> -->
<div
v-if="showApplicationStatus"
class="tui-contact-list-card-right-application"

View File

@@ -133,6 +133,7 @@
Friend,
FriendApplication
} from '@tencentcloud/chat-uikit-engine-lite'
import { navigateTo } from '../../../../utils/router'
const currentContactListKey = ref<keyof IContactList>('')
const currentContactInfo = ref<IContactInfoType>({} as IContactInfoType)
@@ -237,7 +238,8 @@
function toggleCurrentContactList(key: keyof IContactList) {
if (key === 'currentContactSearchingStatus') {
TUIStore.update(StoreName.CUSTOM, key, true)
navigateTo('/pages/adduser/index')
// TUIStore.update(StoreName.CUSTOM, key, true)
return
}
if (currentContactListKey.value === key) {
@@ -290,12 +292,13 @@
}
const selectFriend = (item: any) => {
TUIStore.update(
StoreName.CUSTOM,
'currentContactListKey',
'friendList'
)
selectItem(item)
navigateTo('/pages/adduser/details', { id: item.userID, type: '1' })
// TUIStore.update(
// StoreName.CUSTOM,
// 'currentContactListKey',
// 'friendList'
// )
// selectItem(item)
}
function onDisplayOnlineStatusUpdated(status: boolean) {

View File

@@ -64,6 +64,7 @@
import addCircle from '../../assets/icon/add-friend.svg'
import backSVG from '../../assets/icon/back.svg'
import { CONTACT_INFO_TITLE } from '../../constant'
import { navigateTo } from '../../../utils/router'
const emits = defineEmits(['switchConversation'])
@@ -97,11 +98,12 @@
}
const openContactSearch = () => {
TUIStore.update(
StoreName.CUSTOM,
'currentContactSearchingStatus',
true
)
navigateTo('/pages/adduser/index')
// TUIStore.update(
// StoreName.CUSTOM,
// 'currentContactSearchingStatus',
// true
// )
}
const resetContactType = () => {

View File

@@ -146,8 +146,7 @@
}
})
} else if (item.data.name === 'isAddUser') {
console.log('添加好友')
showDialog('提示', '开发中...')
navigateTo('/pages/adduser/index')
} else {
listener.onClicked(item)
}

View File

@@ -372,6 +372,11 @@
<style lang="scss" scoped>
.group-list {
margin: 0 !important;
.group-list-item {
display: flex;
align-items: center;
border-bottom: 2rpx solid #e5e5e5;
}
}
.popup-content {
display: flex;

View File

@@ -2,8 +2,8 @@
"name" : "密谈IM",
"appid" : "__UNI__9EFDC69",
"description" : "",
"versionName" : "1.0.5",
"versionCode" : 104,
"versionName" : "1.0.6",
"versionCode" : 105,
"transformPx" : false,
/* 5+App */
"app-plus" : {

View File

@@ -437,7 +437,14 @@
{
"path": "pages/adduser/index",
"style": {
"navigationBarTitleText": "添加好友"
"navigationBarTitleText": "添加好友",
"navigationBarBackgroundColor": "#ffffff"
}
},
{
"path": "pages/adduser/details",
"style": {
"navigationBarTitleText": "发送好友申请"
}
},
{
@@ -487,4 +494,4 @@
}
]
}
}
}

403
pages/adduser/details.vue Normal file
View File

@@ -0,0 +1,403 @@
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import TUIChatEngine, {
TUIConversationService,
TUIFriendService,
TUIUserService
} from '@tencentcloud/chat-uikit-engine-lite'
import { useUI } from '../../utils/use-ui'
import { navigateBack, navigateTo, reLaunch } from '@/utils/router'
import { TUIGlobal } from '@tencentcloud/universal-api'
import PopupBox from '../my-index/components/popup-box.vue'
import SwitchBar from '../../TUIKit/components/common/SwitchBar/index.vue'
const { showLoading, hideLoading, showToast, showDialog } = useUI()
const loading = ref(true)
/** 验证信息输入 */
const verificationInfo = ref('')
/** 备注名 */
const remark = ref('')
/** 确认备注信息 */
const confirmRemark = ref('')
/** 用户 id */
const userId = ref('')
/** 好友信息 */
const friendInfo = ref({})
/** 详情页状态 */
const isDetail = ref(false)
/** 黑名单状态 */
const isBlack = ref(false)
/** 点击备注弹框 */
const showRemark = ref(false)
/** 点击查看头像 */
const onViewAvatar = url => {
uni.previewImage({
urls: [url] // 图片路径数组(本地或网络)
})
}
/** 获取好友信息 */
const getFriendInfo = async () => {
loading.value = true
showLoading()
if (isDetail.value) {
TUIFriendService.getFriendProfile({
userIDList: [userId.value]
})
.then(res => {
const data = res.data.friendList[0]
friendInfo.value = data.profile
confirmRemark.value = data.remark
remark.value = data.remark
console.log('好友信息==', data)
})
.finally(() => {
loading.value = false
hideLoading()
})
} else {
TUIUserService.getUserProfile({
userIDList: [userId.value]
})
.then(res => {
friendInfo.value = res.data[0]
console.log('获取好友信息成功', friendInfo.value)
})
.finally(() => {
loading.value = false
hideLoading()
})
}
}
const submit = async () => {
// 在这里可以添加提交验证信息的逻辑
let source = 'AddSource_Type_Web' // 来源渠道
// #ifdef H5
source = 'AddSource_Type_H5'
// #endif
// 判断是否为 App5+ App
// #ifdef APP-PLUS
source = 'AddSource_Type_App'
// #endif
showLoading()
try {
await TUIFriendService.addFriend({
to: userId.value,
source,
remark: remark.value || '',
wording: verificationInfo.value,
type: TUIChatEngine.TYPES.SNS_ADD_TYPE_BOTH
})
hideLoading()
await showToast('好友请求已发送', 'success')
navigateBack()
} catch (error) {
if (error.code === 30515) {
hideLoading()
const show = await showDialog(
'提示',
'该用户在黑名单中,不允许加好友'
)
if (show) {
navigateBack()
}
}
}
}
/** 加入黑名单 */
const switchChange = async () => {
const show = await showDialog(
'提示',
`确定要${isBlack.value ? '移除' : '添加'}黑名单吗?`
)
if (!show) {
return
}
showLoading()
if (isBlack.value) {
TUIUserService.removeFromBlacklist({
userIDList: [friendInfo.value.userID]
})
.then(async () => {
await showToast('移除黑名单成功', 'success')
isBlack.value = false
})
.finally(() => {
hideLoading()
})
} else {
TUIUserService.addToBlacklist({
userIDList: [friendInfo.value.userID]
})
.then(async () => {
await showToast('添加黑名单成功', 'success')
reLaunch('/TUIKit/components/TUIContact/index')
isBlack.value = true
})
.finally(() => {
hideLoading()
})
}
}
/** 备注确认修改 */
const onRemark = () => {
if (remark.value === confirmRemark.value) {
showToast('备注名相同,无法修改')
return
}
showLoading()
TUIFriendService.updateFriend({
userID: friendInfo.value.userID,
remark: remark.value
})
.then(async res => {
await showToast('修改备名成功', 'success')
remark.value = res.data.remark
confirmRemark.value = res.data.remark
})
.finally(() => {
hideLoading()
})
}
/** 删除好友 */
const onDeleteFriend = async () => {
const show = await showDialog('提示', '确定要删除好友吗?')
if (!show) {
return
}
showLoading()
TUIFriendService.deleteFriend({
userIDList: [friendInfo.value.userID],
type: TUIChatEngine.TYPES.SNS_DELETE_TYPE_BOTH
})
.then(async res => {
hideLoading()
const { successUserIDList } = res.data
if (successUserIDList[0].userID === friendInfo.value.userID) {
await showToast('删除好友成功', 'success')
reLaunch('/TUIKit/components/TUIContact/index')
} else {
await showToast('删除好友失败', 'error')
}
})
.catch(async () => {
hideLoading()
await showToast('删除好友失败', 'error')
})
}
/** 发送消息 */
const onSendMessage = () => {
TUIConversationService.switchConversation(
`C2C${friendInfo.value.userID}`
).then(() => {
TUIGlobal?.navigateTo({
url: `/TUIKit/components/TUIChat/index`
})
})
}
onLoad(e => {
userId.value = e?.id || ''
/** type: 不传为添加 1 为详情页 */
isDetail.value = e?.type == 1 || false
uni.setNavigationBarTitle({
title: isDetail.value ? '好友信息' : '发送好友申请'
})
getFriendInfo()
})
</script>
<template>
<view v-if="!loading" class="details-box">
<!-- 顶部用户信息 -->
<view class="top-info">
<image
v-if="friendInfo?.avatar"
:src="friendInfo?.avatar"
mode="aspectFill"
class="avatar"
@tap="onViewAvatar(friendInfo?.avatar)"
></image>
<uni-icons v-else type="contact-filled" size="80"></uni-icons>
<view class="right-box">
<text>{{ friendInfo.nick || '未知名称' }}</text>
<text>手机号: {{ friendInfo.userID }}</text>
<text>
个性签名: {{ friendInfo.selfSignature || '暂无个性签名' }}
</text>
</view>
</view>
<!-- 验证信息输入 -->
<view v-if="!isDetail" class="input-wrapper">
<text class="title">请填写验证信息</text>
<textarea
v-model="verificationInfo"
:maxlength="200"
placeholder="请输入验证信息"
class="input-text"
/>
</view>
<!-- 备注 -->
<view v-if="!isDetail" class="remark">
<text>备注名</text>
<input
v-model="remark"
:maxlength="80"
placeholder="请输入备注名"
placeholder-class="input-placeholder"
/>
</view>
<!-- 发送申请按钮 -->
<view v-if="!isDetail" class="send-btn" @tap="submit">
<text>发送申请</text>
</view>
<!-- 修改好友信息======================== -->
<view v-if="isDetail" class="remark" @click="showRemark = true">
<text>备注名</text>
<view style="display: flex; align-items: center">
<text
style="margin-right: 10rpx; color: #999999; font-size: 28rpx"
>
{{ confirmRemark }}
</text>
<uni-icons type="right" color="#999999" size="36rpx"></uni-icons>
</view>
</view>
<view v-if="isDetail" class="remark">
<text>加入黑名单</text>
<SwitchBar :value="isBlack" @click="switchChange" />
</view>
<view v-if="isDetail" class="send-btn" @tap="onDeleteFriend">
<text style="color: #eb1c26">删除好友</text>
</view>
<bottom-view v-if="isDetail">
<cb-button @click="onSendMessage">发送信息</cb-button>
</bottom-view>
<popup-box
v-model="showRemark"
v-model:name="remark"
title="备注信息"
@confirm="onRemark"
/>
</view>
</template>
<style scoped lang="scss">
// 背景色
page {
background: #f9f9f9;
}
.details-box {
padding: 26rpx 32rpx;
}
.send-btn {
border-radius: 16rpx;
margin-top: 20rpx;
background: #ffffff;
padding: 20rpx 32rpx;
text-align: center;
text {
font-size: 28rpx;
color: #00d993;
}
}
.remark {
border-radius: 16rpx;
margin-top: 20rpx;
background: #ffffff;
padding: 20rpx 32rpx;
display: flex;
justify-content: space-between;
align-items: center;
text {
font-size: 28rpx;
color: #333333;
}
input {
width: 80%;
text-align: right;
}
}
.input-wrapper {
margin-top: 20rpx;
background: #ffffff;
padding: 20rpx 32rpx;
border-radius: 16rpx;
display: flex;
flex-direction: column;
.title {
font-family:
PingFang SC,
PingFang SC;
font-weight: 500;
font-size: 28rpx;
color: #333333;
font-style: normal;
text-transform: none;
margin-bottom: 20rpx;
}
.input-text {
width: calc(100% - 40rpx);
// border: 2rpx solid #eeeeee;
color: #333333;
border-radius: 8rpx;
// padding: 20rpx;
}
}
.top-info {
background: #ffffff;
padding: 20rpx 32rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
.avatar {
flex-shrink: 0;
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
}
.right-box {
height: 100%;
margin-left: 20rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
text {
// 第一个
&:first-child {
font-size: 32rpx;
color: #333333;
}
font-size: 26rpx;
color: #999999;
&:last-child {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
box-orient: vertical;
line-clamp: 1;
overflow: hidden;
}
}
}
}
</style>

View File

@@ -1,216 +1,183 @@
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import TUICore, { TUIConstants } from '@tencentcloud/tui-core-lite'
import { useUI } from '@/utils/use-ui'
import { navigateTo } from '@/utils/router'
import TUIChatEngine, {
TUIFriendService,
TUIUserService
TUIFriendService
} from '@tencentcloud/chat-uikit-engine-lite'
import { useUI } from '../../utils/use-ui'
import { navigateBack } from '@/utils/router'
const { showLoading, hideLoading, showToast } = useUI()
const { showLoading, hideLoading } = useUI()
const loading = ref(false)
const searchValue = ref('')
const searchList = ref([])
const isSearc = ref(false)
// 是否是好友
const isFriend = ref(false)
const loading = ref(true)
/** 验证信息输入 */
const verificationInfo = ref('')
/** 备注名 */
const remark = ref('')
/** 用户 id */
const userId = ref('')
/** 好友信息 */
const friendInfo = ref({})
/** 点击查看头像 */
const onViewAvatar = url => {
uni.previewImage({
urls: [url] // 图片路径数组(本地或网络)
})
const onCancel = () => {
isFriend.value = false
isSearc.value = false
searchList.value = []
}
/** 获取好友信息 */
const getFriendInfo = async () => {
loading.value = true
const search = () => {
if (!searchValue.value) {
return
}
showLoading()
TUIUserService.getUserProfile({
userIDList: [userId.value]
loading.value = true
TUICore.callService({
serviceName: TUIConstants.TUISearch.SERVICE.NAME,
method: TUIConstants.TUISearch.SERVICE.METHOD.SEARCH_USER,
params: {
userID: searchValue.value
}
})
.then(res => {
friendInfo.value = res.data[0]
console.log('获取好友信息成功', friendInfo.value)
isSearc.value = res.data.length === 0
searchList.value = res.data
if (searchList.value.length > 0) {
TUIFriendService.checkFriend({
type: TUIChatEngine.TYPES.SNS_CHECK_TYPE_BOTH,
userIDList: [searchList.value[0].userID]
})
.then(v => {
console.log(v.data.successUserIDList[0])
isFriend.value =
v.data.successUserIDList[0].relation ===
TUIChatEngine.TYPES.SNS_TYPE_BOTH_WAY
hideLoading()
loading.value = false
})
.catch(() => {
loading.value = false
hideLoading()
})
} else {
loading.value = false
hideLoading()
}
})
.finally(() => {
.catch(() => {
loading.value = false
hideLoading()
})
}
const submit = async () => {
// 在这里可以添加提交验证信息的逻辑
let source = 'AddSource_Type_Web' // 来源渠道
// #ifdef H5
source = 'AddSource_Type_H5'
// #endif
// 判断是否为 App5+ App
// #ifdef APP-PLUS
source = 'AddSource_Type_App'
// #endif
showLoading()
await TUIFriendService.addFriend({
to: userId.value,
source,
remark: remark.value || '',
wording: verificationInfo.value,
type: TUIChatEngine.TYPES.SNS_ADD_TYPE_BOTH
})
hideLoading()
await showToast('好友请求已发送', 'success')
navigateBack()
const onAdd = item => {
navigateTo('/pages/adduser/details', { id: item.userID })
}
onLoad(e => {
userId.value = e?.id || '7616mobile'
getFriendInfo()
})
const onDetails = item => {
if (isFriend.value) {
navigateTo('/pages/adduser/details', { id: item.userID, type: '1' })
} else {
onAdd(item)
}
}
</script>
<template>
<view v-if="!loading">
<!-- 顶部用户信息 -->
<view class="top-info">
<image
v-if="friendInfo?.avatar"
:src="friendInfo?.avatar"
mode="aspectFill"
class="avatar"
@tap="onViewAvatar(friendInfo?.avatar)"
></image>
<uni-icons v-else type="contact-filled" size="80"></uni-icons>
<view class="right-box">
<text>{{ friendInfo.nick }}</text>
<text>ID: {{ friendInfo.userID }}</text>
<text>
个性签名: {{ friendInfo.selfSignature || '暂无个性签名' }}
</text>
<view>
<uni-search-bar
v-model="searchValue"
focus
radius="100"
bgColor="#f4f4f4"
textColor="#333333"
placeholder="请输入用户手机号"
@confirm="search"
@cancel="onCancel"
></uni-search-bar>
<cb-empty v-if="isSearc" name="未搜索到此账号"></cb-empty>
<!-- 好友列表 -->
<view v-if="!loading" class="user-list">
<view
v-for="item in searchList"
:key="item.userID"
class="card"
@click="onDetails(item)"
>
<image
v-if="item?.avatar"
:src="item?.avatar"
mode="aspectFill"
class="avatar"
></image>
<view v-else class="avatar">
<uni-icons type="contact-filled" size="130rpx"></uni-icons>
</view>
<view class="right-box">
<view class="name-box">
<text>{{ item.nick || '未知名称' }}</text>
<text>{{ item.userID }}</text>
</view>
<text v-if="isFriend" class="tag">已添加</text>
<button v-else @click.stop="onAdd(item)">添加</button>
</view>
</view>
</view>
<!-- 验证信息输入 -->
<view class="input-wrapper">
<text class="title">请填写验证信息</text>
<textarea
v-model="verificationInfo"
:maxlength="200"
placeholder="请输入验证信息"
class="input-text"
/>
</view>
<!-- 备注 -->
<view class="remark">
<text>备注名</text>
<input
v-model="remark"
:maxlength="80"
placeholder="请输入备注名"
placeholder-class="input-placeholder"
/>
</view>
<!-- 发送申请按钮 -->
<view class="send-btn" @tap="submit">
<text>发送申请</text>
</view>
</view>
</template>
<style scoped lang="scss">
// 背景色
page {
background: #f9f9f9;
}
.send-btn {
margin-top: 20rpx;
background: #ffffff;
padding: 20rpx 32rpx;
text-align: center;
text {
font-size: 28rpx;
color: #2542c0;
}
}
.remark {
margin-top: 20rpx;
background: #ffffff;
padding: 20rpx 32rpx;
display: flex;
justify-content: space-between;
text {
font-size: 28rpx;
color: #333333;
}
input {
width: 80%;
text-align: right;
}
}
.input-wrapper {
margin-top: 20rpx;
background: #ffffff;
padding: 20rpx 32rpx;
display: flex;
flex-direction: column;
.title {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 28rpx;
color: #333333;
font-style: normal;
text-transform: none;
margin-bottom: 20rpx;
}
.input-text {
width: calc(100% - 40rpx);
border: 2rpx solid #eeeeee;
border-radius: 8rpx;
padding: 20rpx;
}
}
.top-info {
background: #ffffff;
padding: 20rpx 32rpx;
display: flex;
align-items: center;
.avatar {
flex-shrink: 0;
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
}
.right-box {
height: 100%;
margin-left: 20rpx;
<style lang="scss" scoped>
.user-list {
padding: 0 48rpx;
.card {
margin-top: 24rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
text {
// 第一个
&:first-child {
align-items: center;
.avatar {
flex-shrink: 0;
width: 96rpx;
height: 96rpx;
border-radius: 96rpx;
margin-right: 16rpx;
display: flex;
justify-content: center;
align-items: center;
}
.right-box {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.tag {
font-size: 32rpx;
color: #333333;
color: #999999;
}
font-size: 26rpx;
color: #999999;
&:last-child {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
box-orient: vertical;
line-clamp: 1;
overflow: hidden;
.name-box {
height: 96rpx;
display: flex;
flex-direction: column;
justify-content: center;
text {
font-weight: 500;
font-size: 32rpx;
color: #333333;
// 最后一个
&:last-child {
margin-top: 6rpx;
font-weight: 400;
font-size: 24rpx;
color: #999999;
}
}
}
button {
margin: 0;
width: 128rpx;
height: 64rpx;
line-height: 64rpx;
background: linear-gradient(0deg, #00d993 0%, #00d9c5 100%);
border-radius: 100rpx;
font-weight: 500;
font-size: 28rpx;
color: #ffffff;
&::after {
border: none;
}
}
}
}

View File

@@ -19,13 +19,6 @@
]
const onGo = item => {
// ============测试添加好友===============
// if (item === 'project') {
// navigateTo('/pages/adduser/index')
// return
// }
// ===========================
if (item === 'project') {
showDialog('提示', '外部链接暂未提供', false)
return

View File

@@ -13,6 +13,7 @@
const getList = async () => {
const res = await getUserServiceFree()
customerData.value = res?.data || {}
console.log( customerData.value)
}
const handleSwitchConversation = async () => {

View File

@@ -21,7 +21,7 @@
</view>
<view class="code-img">
<l-qrcode
:value="`/pages/adduser/index?id=${tencentUserSig.userId}`"
:value="`/pages/adduser/details?id=${tencentUserSig.userId}`"
size="240"
/>
</view>

View File

@@ -0,0 +1,47 @@
## 1.3.02024-04-22
- 修复 textColor默认值导致的文字不显示的bug
## 1.2.92024-04-17
- 修复 textColor不生效的bug
## 1.2.82024-02-22
- 修复 清空按钮emit值错误的bug
## 1.2.72024-02-21
- 新增 设置输入框字体颜色:textColor
## 1.2.62024-02-20
- 修复 uni-search-bar在支付宝小程序下样式兼容问题
## 1.2.52024-01-31
- 修复 uni-search-bar居中问题现在默认居左并修复样式偏移问题
## 1.2.42023-05-09
- 修复 i18n 国际化不正确的 Bug
## 1.2.32022-05-24
- 新增 readonly 属性,组件只读
## 1.2.22022-05-06
- 修复 vue3 input 事件不生效的bug
## 1.2.12022-05-06
- 修复 多余代码导致的bug
## 1.2.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-search-bar](https://uniapp.dcloud.io/component/uniui/uni-search-bar)
## 1.1.22021-08-30
- 修复 value 属性与 modelValue 属性不兼容的Bug
## 1.1.12021-08-24
- 新增 支持国际化
## 1.1.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.92021-05-12
- 新增 项目示例地址
## 1.0.82021-04-21
- 优化 添加依赖 uni-icons, 导入后自动下载依赖
## 1.0.72021-04-15
- uni-ui 新增 uni-search-bar 的 focus 事件
## 1.0.62021-02-05
- 优化 组件引用关系通过uni_modules引用组件
## 1.0.52021-02-05
- 调整为uni_modules目录规范
- 新增 支持双向绑定
- 更改 input 事件的返回值e={value:Number} --> e=value
- 新增 支持图标插槽
- 新增 支持 clear、blur 事件
- 新增 支持 focus 属性
- 去掉组件背景色

View File

@@ -0,0 +1,4 @@
{
"uni-search-bar.cancel": "cancel",
"uni-search-bar.placeholder": "Search enter content"
}

View File

@@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}

View File

@@ -0,0 +1,4 @@
{
"uni-search-bar.cancel": "取消",
"uni-search-bar.placeholder": "请输入搜索内容"
}

View File

@@ -0,0 +1,4 @@
{
"uni-search-bar.cancel": "取消",
"uni-search-bar.placeholder": "請輸入搜索內容"
}

View File

@@ -0,0 +1,309 @@
<template>
<view class="uni-searchbar">
<view :style="{borderRadius:radius+'px',backgroundColor: bgColor}" class="uni-searchbar__box"
@click="searchClick">
<view class="uni-searchbar__box-icon-search">
<slot name="searchIcon">
<uni-icons color="#c0c4cc" size="18" type="search" />
</slot>
</view>
<input v-if="show || searchVal" :focus="showSync" :disabled="readonly" :placeholder="placeholderText" :maxlength="maxlength"
class="uni-searchbar__box-search-input" confirm-type="search" type="text" v-model="searchVal" :style="{color:textColor}"
@confirm="confirm" @blur="blur" @focus="emitFocus"/>
<text v-else class="uni-searchbar__text-placeholder">{{ placeholder }}</text>
<view v-if="show && (clearButton==='always'||clearButton==='auto'&&searchVal!=='') &&!readonly"
class="uni-searchbar__box-icon-clear" @click="clear">
<slot name="clearIcon">
<uni-icons color="#c0c4cc" size="20" type="clear" />
</slot>
</view>
</view>
<text @click="cancel" class="uni-searchbar__cancel"
v-if="cancelButton ==='always' || show && cancelButton ==='auto'">{{cancelTextI18n}}</text>
</view>
</template>
<script>
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from './i18n/index.js'
const {
t
} = initVueI18n(messages)
/**
* SearchBar 搜索栏
* @description 搜索栏组件,通常用于搜索商品、文章等
* @tutorial https://ext.dcloud.net.cn/plugin?id=866
* @property {Number} radius 搜索栏圆角
* @property {Number} maxlength 输入最大长度
* @property {String} placeholder 搜索栏Placeholder
* @property {String} clearButton = [always|auto|none] 是否显示清除按钮
* @value always 一直显示
* @value auto 输入框不为空时显示
* @value none 一直不显示
* @property {String} cancelButton = [always|auto|none] 是否显示取消按钮
* @value always 一直显示
* @value auto 输入框不为空时显示
* @value none 一直不显示
* @property {String} cancelText 取消按钮的文字
* @property {String} bgColor 输入框背景颜色
* @property {String} textColor 输入文字颜色
* @property {Boolean} focus 是否自动聚焦
* @property {Boolean} readonly 组件只读,不能有任何操作,只做展示
* @event {Function} confirm uniSearchBar 的输入框 confirm 事件返回参数为uniSearchBar的valuee={value:Number}
* @event {Function} input uniSearchBar 的 value 改变时触发事件返回参数为uniSearchBar的valuee=value
* @event {Function} cancel 点击取消按钮时触发事件返回参数为uniSearchBar的valuee={value:Number}
* @event {Function} clear 点击清除按钮时触发事件返回参数为uniSearchBar的valuee={value:Number}
* @event {Function} blur input失去焦点时触发事件返回参数为uniSearchBar的valuee={value:Number}
*/
export default {
name: "UniSearchBar",
emits: ['input', 'update:modelValue', 'clear', 'cancel', 'confirm', 'blur', 'focus'],
props: {
placeholder: {
type: String,
default: ""
},
radius: {
type: [Number, String],
default: 5
},
clearButton: {
type: String,
default: "auto"
},
cancelButton: {
type: String,
default: "auto"
},
cancelText: {
type: String,
default: ""
},
bgColor: {
type: String,
default: "#F8F8F8"
},
textColor: {
type: String,
default: "#000000"
},
maxlength: {
type: [Number, String],
default: 100
},
value: {
type: [Number, String],
default: ""
},
modelValue: {
type: [Number, String],
default: ""
},
focus: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
}
},
data() {
return {
show: false,
showSync: false,
searchVal: ''
}
},
computed: {
cancelTextI18n() {
return this.cancelText || t("uni-search-bar.cancel")
},
placeholderText() {
return this.placeholder || t("uni-search-bar.placeholder")
}
},
watch: {
// #ifndef VUE3
value: {
immediate: true,
handler(newVal) {
this.searchVal = newVal
if (newVal) {
this.show = true
}
}
},
// #endif
// #ifdef VUE3
modelValue: {
immediate: true,
handler(newVal) {
this.searchVal = newVal
if (newVal) {
this.show = true
}
}
},
// #endif
focus: {
immediate: true,
handler(newVal) {
if (newVal) {
if(this.readonly) return
this.show = true;
this.$nextTick(() => {
this.showSync = true
})
}
}
},
searchVal(newVal, oldVal) {
this.$emit("input", newVal)
// #ifdef VUE3
this.$emit("update:modelValue", newVal)
// #endif
}
},
methods: {
searchClick() {
if(this.readonly) return
if (this.show) {
return
}
this.show = true;
this.$nextTick(() => {
this.showSync = true
})
},
clear() {
this.searchVal = ""
this.$nextTick(() => {
this.$emit("clear", { value: "" })
})
},
cancel() {
if(this.readonly) return
this.$emit("cancel", {
value: this.searchVal
});
this.searchVal = ""
this.show = false
this.showSync = false
// #ifndef APP-PLUS
uni.hideKeyboard()
// #endif
// #ifdef APP-PLUS
plus.key.hideSoftKeybord()
// #endif
},
confirm() {
// #ifndef APP-PLUS
uni.hideKeyboard();
// #endif
// #ifdef APP-PLUS
plus.key.hideSoftKeybord()
// #endif
this.$emit("confirm", {
value: this.searchVal
})
},
blur() {
// #ifndef APP-PLUS
uni.hideKeyboard();
// #endif
// #ifdef APP-PLUS
plus.key.hideSoftKeybord()
// #endif
this.$emit("blur", {
value: this.searchVal
})
},
emitFocus(e) {
this.$emit("focus", e.detail)
}
}
};
</script>
<style lang="scss">
$uni-searchbar-height: 36px;
.uni-searchbar {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
position: relative;
padding: 10px;
// background-color: #fff;
}
.uni-searchbar__box {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
justify-content: left;
/* #endif */
overflow: hidden;
position: relative;
flex: 1;
flex-direction: row;
align-items: center;
height: $uni-searchbar-height;
padding: 5px 8px 5px 0px;
}
.uni-searchbar__box-icon-search {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
// width: 32px;
padding: 0 8px;
justify-content: center;
align-items: center;
color: #B3B3B3;
}
.uni-searchbar__box-search-input {
flex: 1;
font-size: 14px;
color: #333;
margin-left: 5px;
margin-top: 1px;
/* #ifndef APP-NVUE */
background-color: inherit;
/* #endif */
}
.uni-searchbar__box-icon-clear {
align-items: center;
line-height: 24px;
padding-left: 8px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-searchbar__text-placeholder {
font-size: 14px;
color: #B3B3B3;
margin-left: 5px;
text-align: left;
}
.uni-searchbar__cancel {
padding-left: 10px;
line-height: $uni-searchbar-height;
font-size: 14px;
color: #333333;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
</style>

View File

@@ -0,0 +1,87 @@
{
"id": "uni-search-bar",
"displayName": "uni-search-bar 搜索栏",
"version": "1.3.0",
"description": "搜索栏组件,通常用于搜索商品、文章等",
"keywords": [
"uni-ui",
"uniui",
"搜索框",
"搜索栏"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [
"uni-scss",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y",
"alipay": "n"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@@ -0,0 +1,14 @@
## SearchBar 搜索栏
> **组件名uni-search-bar**
> 代码块: `uSearchBar`
搜索栏组件
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-search-bar)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839