2025/2/8第一次更新

This commit is contained in:
爱吃咸鱼小猫咪
2025-02-08 18:50:38 +08:00
commit d7af560866
26519 changed files with 5046029 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
## 1.0.0
- 首版发布
+13
View File
@@ -0,0 +1,13 @@
Copyright (c) 2023-present Tuniao Technology
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+130
View File
@@ -0,0 +1,130 @@
# 图鸟 UI vue3 uniapp Plugins - 悬浮按钮
![TuniaoUI vue3 uniapp](https://resource.tuniaokj.com/images/vue3/market/vue3-banner-min.jpg 'TuniaoUI vue3 uniapp')
[Tuniao UI vue3官方仓库](https://github.com/tuniaoTech/tuniaoui-rc-vue3-uniapp)
该组件一般用于将按钮现在是页面的指定位置,方便用户进行跳转等操作
## 组件安装
```bash
npm install tnuiv3p-tn-suspend-button
```
## 组件位置
```typescript
import TnSuspendButton from 'tnuiv3p-tn-suspend-button/index.vue'
```
## 平台差异说明
| App(vue) | H5 | 微信小程序 | 支付宝小程序 | ... |
| :------: | :-: | :--------: | :----------: | :----: |
| √ | √ | √ | √ | 适配中 |
## 基础使用
- 通过`icon`属性可以设置按钮显示的图标,可以在默认的插槽中设置按钮的内容
```vue
<script setup lang="ts"></script>
<template>
<TnSuspendButton icon="logo-tuniao" />
</template>
```
## 修改按钮的位置
- 通过`top``right`属性可以设置悬浮按钮距离顶部和右边的距离, 默认单位为`rpx`, 也可以是一个具体的值
```vue
<script setup lang="ts"></script>
<template>
<TnSuspendButton icon="logo-tuniao" top="90%" right="30" />
</template>
```
## 修改按钮的样式
- 通过`bg-color`属性可以修改按钮的背景颜色
- 通过`text-color`属性可以修改按钮的文字颜色
- 通过`size`属性可以设置按钮的大小,默认单位为`rpx`, 内置`sm``lg``xl`
```vue
<script setup lang="ts"></script>
<template>
<TnSuspendButton icon="logo-tuniao" size="sm" />
</template>
```
```vue
<script setup lang="ts"></script>
<template>
<TnSuspendButton icon="logo-tuniao" size="140" />
</template>
```
## 修改按钮的形状
- 通过`shape`属性可以修改按钮的形状,默认为`circle`,内置`circle``square`
```vue
<script setup lang="ts"></script>
<template>
<TnSuspendButton icon="logo-tuniao" shaepe="square" />
</template>
```
## 修改按钮的定位方式
- 通过`fixed`参数可以设置按钮是相对于页面还是相对于父元素进行定位,默认为`true`,即相对于页面进行定位
```vue
<script setup lang="ts"></script>
<template>
<TnSuspendButton icon="logo-tuniao" :fixed="false" />
</template>
```
## API
### Props
| 属性名 | 说明 | 类型 | 默认值 | 可选值 |
| ---------- | ------------------------------------------------------------ | ------- | ----------------- | ------------------------------------------------------------ |
| icon | 按钮显示的图标 | String | - | [图标有效值](https://vue3.tuniaokj.com/zh-CN/component/icon.html) |
| top | 按钮距离顶部的距离,默认单位为`rpx` | String | 80% | - |
| right | 按钮距离右边的距离,默认单位为`rpx` | String | 5% | - |
| bg-color | 按钮背景颜色,可以使用图鸟内置的[背景色](https://vue3.tuniaokj.com/zh-CN/guide/style/background.html)、hex、rgb、rgba | String | `tn-type-primary` | - |
| text-color | 按钮文字的颜色,支持图鸟内置的[颜色值](https://vue3.tuniaokj.com/zh-CN/guide/style/text.html)、hex、rgb、rgba | String | `tn-color-white` | - |
| size | 按钮的尺寸,默认单位为`rpx`,内置了`sm``lg``xl` | String | - | `sm``lg``xl` |
| shape | 按钮的形状 | String | `circle` | `shape` |
| opacity | 按钮的透明度 | Number | `0.9` | - |
| shadow | 是否显示阴影 | Boolean | `true` | `false` |
| float | 是否显示漂浮的动画 | Boolean | `true` | `false` |
| fixed | 是否固定位置 | Boolean | `true` | `false` |
### Slots
| 插槽名 | 说明 |
| ------- | ---------- |
| default | 按钮的内容 |
### Emits
| 事件名 | 说明 | 类型 |
| ------ | ------------ | ------------ |
| click | 按钮点击事件 | `() => void` |
+2
View File
@@ -0,0 +1,2 @@
export * from './suspend-button-custom'
export * from './use-suspend-button'
@@ -0,0 +1,109 @@
import { computed, toRef } from 'vue'
import {
useComponentColor,
useComponentSize,
useNamespace,
} from '@tuniao/tnui-vue3-uniapp/hooks'
import { formatDomSizeValue } from '@tuniao/tnui-vue3-uniapp/utils'
import type { CSSProperties } from 'vue'
import type { SuspendButtonProps } from '../types'
export const useSuspendButtonCustomStyle = (props: SuspendButtonProps) => {
const ns = useNamespace('suspend-button')
// 解析颜色
const [bgColorClass, bgColorStyle] = useComponentColor(
toRef(props, 'bgColor'),
'bg'
)
const [textColorClass, textColorStyle] = useComponentColor(
toRef(props, 'textColor'),
'text'
)
// 解析尺寸
const { sizeType } = useComponentSize(props.size)
// 按钮对应的类和样式
const buttonClass = computed<string>(() => {
const cls: string[] = [ns.b()]
if (bgColorClass.value) {
cls.push(bgColorClass.value)
}
if (textColorClass.value) {
cls.push(textColorClass.value)
}
if (props.shape) {
cls.push(ns.m(props.shape))
}
if (props.size && sizeType.value === 'inner') {
cls.push(ns.m(props.size))
}
if (props.float) {
cls.push(ns.m('float'))
}
if (props.fixed) {
cls.push(ns.m('fixed'))
}
if (props.shadow) {
cls.push('tn-shadow')
}
return cls.join(' ')
})
const buttonStyle = computed<CSSProperties>(() => {
const style: CSSProperties = {}
if (!bgColorClass.value) {
style.backgroundColor = bgColorStyle.value || 'var(--tn-color-primary)'
}
if (textColorStyle.value) {
style.color = textColorStyle.value
} else if (!bgColorClass.value && !textColorClass.value) {
style.color = 'var(--tn-color-white)'
}
if (props.size && sizeType.value === 'custom') {
style.width = style.height = formatDomSizeValue(props.size)
}
if (props?.opacity !== undefined) {
style.opacity = props.opacity
}
if (props?.top !== undefined) {
style.top = formatDomSizeValue(props.top)
}
if (props?.right !== undefined) {
style.right = formatDomSizeValue(props.right)
}
return style
})
// 图标对应的类和样式
const iconClass = computed<string>(() => {
const cls: string[] = [ns.e('icon')]
return cls.join(' ')
})
const iconStyle = computed<CSSProperties>(() => {
const style: CSSProperties = {}
if (props.size && sizeType.value === 'custom') {
style.fontSize = `calc(${formatDomSizeValue(props.size)} * 0.7)`
}
return style
})
return {
buttonClass,
buttonStyle,
iconClass,
iconStyle,
}
}
@@ -0,0 +1,14 @@
import type { SetupContext } from 'vue'
import type { SuspendButtonEmits } from '../types'
export const useSuspendButton = (
emits: SetupContext<SuspendButtonEmits>['emit']
) => {
const clickHandle = () => {
emits('click')
}
return {
clickHandle,
}
}
+8
View File
@@ -0,0 +1,8 @@
import { withNoopInstall } from '@tuniao/tnui-vue3-uniapp/utils'
import suspendButton from './index.vue'
export const TnSuspendButton = withNoopInstall(suspendButton)
export default TnSuspendButton
export * from './types'
export type { TnSuspendButtonInstance } from './instance'
+26
View File
@@ -0,0 +1,26 @@
<script lang="ts" setup>
import TnIcon from '@tuniao/tnui-vue3-uniapp/components/icon/src/icon.vue'
import { suspendButtonEmits, suspendButtonProps } from './types'
import { useSuspendButton, useSuspendButtonCustomStyle } from './composables'
const props = defineProps(suspendButtonProps)
const emits = defineEmits(suspendButtonEmits)
const { buttonClass, buttonStyle, iconClass, iconStyle } =
useSuspendButtonCustomStyle(props)
const { clickHandle } = useSuspendButton(emits)
</script>
<template>
<view :class="[buttonClass]" :style="buttonStyle" @tap="clickHandle">
<slot>
<view :class="[iconClass]" :style="iconStyle">
<TnIcon :name="$props.icon" />
</view>
</slot>
</view>
</template>
<style lang="scss" scoped>
@import './theme-chalk/index.scss';
</style>
+3
View File
@@ -0,0 +1,3 @@
import type SuspendButton from './index.vue'
export type TnSuspendButtonInstance = InstanceType<typeof SuspendButton>
+34
View File
@@ -0,0 +1,34 @@
{
"name": "tnuiv3p-tn-suspend-button",
"version": "1.0.0",
"description": "TuniaoUI vue3 uniapp 插件",
"keywords": [
"tn",
"tuniao",
"tuniao-ui",
"图鸟",
"uniapp",
"uniapp插件"
],
"license": "Apache 2.0",
"author": "Tuniao Technology Co., Ltd.",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/HighSpecific/tnuiv3p-suspend-button"
},
"bugs": {
"url": "https://github.com/HighSpecific/tnuiv3p-suspend-button/issues"
},
"peerDependencies": {
"@tuniao/tn-icon": "^1.4.0",
"@tuniao/tn-style": "^1.0.17",
"@tuniao/tnui-vue3-uniapp": "^1.0.15",
"sass": "^1.61.0",
"typescript": "^5.1.6",
"vue": "^3.2.47"
},
"gitHead": ""
}
+84
View File
@@ -0,0 +1,84 @@
@use 'sass:map';
@use './mixins/mixins.scss' as *;
$tn-inner-sizes: 'sm', 'lg', 'xl';
$suspend-button-sizes: () !default;
$suspend-button-sizes: map.merge(
(
'sm': (
size: 80rpx,
icon-size: 50rpx,
),
'': (
size: 100rpx,
icon-size: 60rpx,
),
'lg': (
size: 120rpx,
icon-size: 80rpx,
),
'xl': (
size: 140rpx,
icon-size: 90rpx,
),
),
$suspend-button-sizes
);
@include b(suspend-button) {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
width: map-get(map-get($suspend-button-sizes, ''), size);
height: map-get(map-get($suspend-button-sizes, ''), size);
@include e(icon) {
font-size: map-get(map-get($suspend-button-sizes, ''), icon-size);
}
/* 动画 */
@include m(float) {
animation: suspend-button-float 4s ease-in-out infinite;
}
/* 尺寸 */
@each $size in $tn-inner-sizes {
@include m($size) {
width: map-get(map-get($suspend-button-sizes, $size), size);
height: map-get(map-get($suspend-button-sizes, $size), size);
@include e(icon) {
font-size: map-get(map-get($suspend-button-sizes, $size), icon-size);
}
}
}
/* 绝对位置 */
@include m(fixed) {
position: fixed;
}
/* 形状 */
@include m(circle) {
border-radius: 50%;
}
@include m(square) {
border-radius: 8rpx;
}
}
/* 上下漂浮的动画 */
@keyframes suspend-button-float {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-30rpx);
}
100% {
transform: translateY(0);
}
}
@@ -0,0 +1,5 @@
$namespace: 'tn' !default;
$common-separator: '-' !default;
$element-separator: '__' !default;
$modifier-separator: '--' !default;
$state-prefix: 'is-' !default;
+105
View File
@@ -0,0 +1,105 @@
@use 'config';
// BEM support Func
// 块(Block):代表一个独立的组件或页面中的一个大型部分。块可以看作是一个命名空间,用于包含相关元素和修饰符。例如,一个导航栏可以被视为一个块。
// 元素(Element):代表块的一部分,但不能独立存在。元素总是属于一个块,并且与该块紧密相关。元素由块名称和元素名称组成,中间由双下划线(__)连接。例如,一个导航栏可以包含多个链接,链接可以被视为导航栏块的元素。
// 修饰符(Modifier):代表块或元素的变体或状态。修饰符用于修改块或元素的外观或行为。修饰符由块名称或元素名称,连字符(-)和修饰符名称组成。例如,一个导航栏可以具有活动状态或浅色主题,这些状态可以通过添加修饰符类进行实现。
@function selectorToString($selector) {
$selector: inspect($selector);
$selector: str-slice($selector, 2, -2);
@return $selector;
}
@function containsModifier($selector) {
$selector: selectorToString($selector);
@if str_index($selector, config.$modifier-separator) {
@return true;
} @else {
@return false;
}
}
@function containWhenFlag($selector) {
$selector: selectorToString($selector);
@if str-index($selector, '.' + config.$state-prefix) {
@return true;
} @else {
@return false;
}
}
@function containPseudoClass($selector) {
$selector: selectorToString($selector);
@if str-index($selector, ':') {
@return true;
} @else {
@return false;
}
}
@function hitAllSpecialNestRule($selector) {
@return containsModifier($selector) or containWhenFlag($selector) or
containPseudoClass($selector);
}
// join var name
// joinVarName(('button', 'text-color')) => '--tn-button-text-color'
@function joinVarName($list) {
$name: '--' + config.$namespace;
@each $item in $list {
@if $item != '' {
$name: $name + '-' + $item;
}
}
@return $name;
}
// getCssVarName('button', 'text-color') => '--tn-button-text-color'
@function getCssVarName($args...) {
@return joinVarName($args);
}
// getCssVar('button', 'text-color') => var(--tn-button-text-color)
@function getCssVar($args...) {
@return var(#{joinVarName($args)});
}
// getCssVarWithDefault('button', 'text-color', 'red') => var(--tn-button-text-color, red)
@function getCssVarWithDefault($args, $default) {
@return var(#{joinVarName($args)}, #{$default});
}
// bem('block', 'element', ''modifier) => 'tn-block__element--modifier'
@function bem($block, $element: '', $modifier: '') {
$name: config.$namespace + config.$common-separator + $block;
@if $element != '' {
$name: $name + config.$element-separator + $element;
}
@if $modifier != '' {
$name: $name + config.$modifier-separator + $modifier;
}
@return $name;
}
// 字符串替换
@function str-replace($string, $search, $replace) {
$index: str-index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace +
str-replace(
str-slice($string, $index + str-length($search)),
$search,
$replace
);
}
@return $string;
}
+134
View File
@@ -0,0 +1,134 @@
@use 'function' as *;
// forward mixins
@forward 'config';
@forward 'function';
@use 'config' as *;
// BEM
@mixin b($block) {
$B: $namespace + '-' + $block !global;
.#{$B} {
@content;
}
}
@mixin e($element) {
$E: $element !global;
$selector: &;
$currentSelector: '';
@each $unit in $element {
$currentSelector: #{$currentSelector +
'.' +
$B +
$element-separator +
$unit +
','};
}
@if hitAllSpecialNestRule($selector) {
@at-root {
#{$selector} {
#{$currentSelector} {
@content;
}
}
}
} @else {
@at-root {
#{$currentSelector} {
@content;
}
}
}
}
@mixin m($modifier) {
$selector: &;
$currentSelector: '';
@each $unit in $modifier {
$currentSelector: #{$currentSelector +
$selector +
$modifier-separator +
$unit +
','};
}
@at-root {
#{$currentSelector} {
@content;
}
}
}
@mixin configurable-m($modifier, $E-flag: false) {
$selector: &;
$interpolation: '';
@if $E-flag {
$interpolation: $element-separator + $E-flag;
}
@at-root {
#{$selector} {
.#{$B + $interpolation + $modifier-separator + $modifier} {
@content;
}
}
}
}
@mixin spec-selector(
$specSelector: '',
$element: $E,
$modifier: false,
$block: $B
) {
$modifierCombo: '';
$elementCombo: '';
@if $modifier {
$modifierCombo: $modifier-separator + $modifier;
}
@if $element {
$elementCombo: $element-separator + $element;
}
@at-root {
#{&}#{$specSelector}.#{$block + $elementCombo + $modifierCombo} {
@content;
}
}
}
@mixin meb($modifier: false, $element: $E, $block: $B) {
$selector: &;
$modifierCombo: '';
@if $modifier {
$modifierCombo: $modifier-separator + $modifier;
}
@at-root {
#{$selector} {
.#{$block + $element-separator + $element + $modifierCombo} {
@content;
}
}
}
}
@mixin when($state) {
@at-root {
&.#{$state-prefix + $state} {
@content;
}
}
}
@mixin pseudo($pseudo) {
@at-root #{&}#{':#{$pseudo}'} {
@content;
}
}
+91
View File
@@ -0,0 +1,91 @@
import { buildProps } from '@tuniao/tnui-vue3-uniapp/utils'
import type { ExtractPropTypes } from 'vue'
export const suspendButtonShape = ['circle', 'square'] as const
export type SuspendButtonShape = (typeof suspendButtonShape)[number]
export const suspendButtonProps = buildProps({
/**
* @description 按钮显示的图标
*/
icon: String,
/**
* @description 按钮距离顶部的位置,单位rpx
*/
top: {
type: [String, Number],
default: '80%',
},
/**
* @description 按钮距离右侧的位置,单位rpx
*/
right: {
type: [String, Number],
default: '5%',
},
/**
* @description 按钮背景颜色, 以tn开头使用图鸟内置的颜色
*/
bgColor: {
type: String,
default: 'tn-type-primary',
},
/**
* @description 按钮文字颜色, 以tn开头使用图鸟内置的颜色
*/
textColor: {
type: String,
default: 'tn-color-white',
},
/**
* @description 按钮尺寸, 内置尺寸sm、lg、xl, 也可以传入指定尺寸的数值,默认单位为rpx
*/
size: String,
/**
* @description 按钮形状
*/
shape: {
type: String,
values: suspendButtonShape,
default: 'circle',
},
/**
* @description 透明度
*/
opacity: {
type: Number,
default: 0.9,
},
/**
* @description 是否显示阴影
*/
shadow: {
type: Boolean,
default: true,
},
/**
* @description 是否有漂浮动画
*/
float: {
type: Boolean,
default: true,
},
/**
* @description 是否固定位置
*/
fixed: {
type: Boolean,
default: true,
},
})
export const suspendButtonEmits = {
/**
* @description 点击按钮时触发
*/
click: () => true,
}
export type SuspendButtonProps = ExtractPropTypes<typeof suspendButtonProps>
export type SuspendButtonEmits = typeof suspendButtonEmits