小程序写法对照指南
一、状态值
- 小程序
- Vue-Options
- Vue-Composition
- React-Hook
// index.wxml
<view>
<text>{{ count }}</text>
<button bindtap="handleAdd">+1</button>
</view>
// index.js
Component({
data: {
count: 0,
},
methods: {
handleAdd() {
this.setData({
count: this.data.count + 1,
});
},
},
});
<template>
<span>{{ count }}</span>
<button @click="handleAdd">+1</button>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
handleAdd() {
this.count += 1
}
}
}
</script>
<template>
<span>{{ count }}</span>
<button @click="handleAdd">+1</button>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
const handleAdd = () => {
count.value += 1
}
</script>
import React, { useState } from 'react'
const App = (props) => {
const [count, setCount] = useState(0)
const handleAdd = () => {
setCount(count + 1)
}
return (
<>
<span>{count}</span>
<button onClick={handleAdd}>+1</button>
</>
)
}
export default App
二、显示隐藏
- 小程序
- Vue
- React
<view>
<i-button wx:if="{{show}}">按钮</i-button>
<i-button wx:if="{{show}}">显示</i-button>
<i-button wx:else>隐藏</i-button>
</view>
<template>
<i-button v-if="show">按钮</i-button>
<i-button v-if="show">显示</i-button>
<i-button v-else>隐藏</i-button>
</template>
<>
{show && <Button>按钮</Button>}
{show ? <Button>显示</Button> : <Button>隐藏</Button>}
</>
三、属性传值
- 小程序
- Vue
- React
<i-button type="primary">按钮</i-button>
<i-button disabled>按钮</i-button>
<i-button loading="{{true}}">按钮</i-button>
<i-button name="{{getName()}}">按钮</i-button>
<i-button bindtap="handleAdd">按钮</i-button>
<i-button type="primary">按钮</i-button>
<i-button disabled>按钮</i-button>
<i-button :loading="true">按钮</i-button>
<i-button :name={getName()}>按钮</i-button>
<i-button @click="handleAdd">按钮</i-button>
<Button type="primary">按钮</Button>
<Button disabled>按钮</Button>
<Button loading={true}>按钮</Button>
<Button name={getName()}>按钮</Button>
<Button onClick={handleAdd}>按钮</Button>
四、类名 & 样式
- 小程序
- Vue
- React
<view
class="i-button i-button--type-{{type}}"
>
按钮
</view>
<view
style="width: 300rpx; font-size: 16px;"
>
按钮
</view>
<div
:class="[
'i-button',
`i-button--type-${type}`
]"
>
按钮
</div>
<div
:style="{
width: '300px',
fontSize: '16px'
}"
>
按钮
</div>
<div
className={classNames(
'i-button',
`i-button--type-${type}`,
className,
)}
>
按钮
</div>
<div
style={{
width: 300,
fontSize: 16
}}
>
按钮
</div>
五、插槽
1、默认插槽
- 小程序
- Vue
- React
// index.wxml
<view>
<slot />
</view>
<template>
<div>
<slot />
</div>
</template>
<style lang="scss">
@import './index.scss';
</style>
import React from 'react';
const Button = (props) => {
const {
children,
} = props;
return (
<div>
{children}
</div>
);
};
Button.displayName = 'Button';
export default Button;
2、具名插槽
2-1、定义
- 小程序
- Vue
- React
注意 :::
在微信小程序中,由于 WXML 语法的限制,<slot>
必须写成 <slot></slot>
,不能写成 <slot />
。
// /components/i-button/i-button.wxml
<view>
<slot name="prefixContent"></slot>
<slot></slot>
<slot name="suffixContent"></slot>
</view>
// /components/i-button/i-button.js
Component({
options: {
multipleSlots: true // 启用多插槽支持
},
properties: {
// 组件的属性
},
data: {
// 组件的初始数据
},
methods: {
// 组件的方法
}
});
// /components/i-button/i-button.json
{
"component": true
}
<template>
<div>
<slot name="prefixContent" />
<slot />
<slot name="suffixContent" />
</div>
</template>
<style lang="scss">
@import './index.scss';
</style>
import React from 'react';
const Button = (props) => {
const {
children,
prefixContent,
suffixContent
} = props;
return (
<div>
{prefixContent}
{children}
{suffixContent}
</div>
);
};
Button.displayName = 'Button';
export default Button;
2-2、使用
- 小程序
- Vue
- React
// index.wxml
<view>
<i-button>
<view slot="prefixContent">
搜索
</view>
按钮
<view slot="suffixContent">
<i-icon name="Search"></i-icon>
</view>
</i-button>
</view>
// index.json
{
"usingComponents": {
"i-button": "/components/i-button/i-button",
"i-icon": "/components/i-icon/i-icon"
}
}
<template>
<Button>
<template #prefixContent>
搜索
</template>
按钮
<template #suffixContent>
<Icon name="Search" />
</template>
</Button>
</template>
<script setup>
import Button from './button.vue'
import Icon from './icon.vue'
</script>
import React from 'react';
import Button from './Button.jsx'
import Icon from './Icon.jsx'
const App = () => {
const suffixIcon = <Icon name="Search" />;
return (
<Button
prefixContent="搜索"
suffixContent={suffixIcon}
>
按钮
</Button>
);
};
export default App;
六、Props
- 小程序
- Vue
- React
// i-button.wxml
<button
class="i-button i-button--size-{{size}} {{className}}"
style="{{style}}"
disabled="{{disabled}}"
>
<slot></slot>
</button>
// i-button.js
Component({
externalClasses: ['className'],
properties: {
// 是否禁用
disabled: {
type: Boolean,
value: false
},
// 按钮尺寸
size: {
type: String,
value: 'medium',
options: ['small', 'medium', 'large']
},
// 自定义样式
style: {
type: String,
value: ''
}
}
})
// i-button.json
{
"component": true,
"usingComponents": {}
}
// 使用
<view>
<i-button
size="large"
disabled="{{false}}"
className="custom-class"
style="color: red;"
>
按钮文字
</i-button>
</view>
<template>
<button
:class="[
'i-button',
`i-button--size-${size}`,
]"
>
<slot />
</button>
</template>
<script setup lang="ts">
/**
* 注意这里的 ButtonProps 无法从 type.ts 中引入
* 只能写在这个 .vue 文件中
* 详情见 https://github.com/vuejs/core/issues/4294
*/
interface ButtonProps {
/**
* 是否禁用按钮
* @default false
*/
disabled?: boolean
/**
* 按钮尺寸
* @default medium
*/
size?: 'small' | 'medium' | 'large'
}
const {
disabled = false,
size = 'medium',
} = defineProps<ButtonProps>()
</script>
<style lang="scss">
@import './index.scss';
</style>
// 使用
<i-button type="primary">按钮</i-button>
<i-button disabled>按钮</i-button>
<i-button :loading="true">按钮</i-button>
<i-button :name={getName()}>按钮</i-button>
import React from 'react';
import classNames from 'classnames';
import './index.scss';
/**
* 这里的 ButtonProps 可以从 type.ts 引入
* import { ButtonProps } from './type.ts'
*/
interface ButtonProps {
/**
* 类名
*/
className?: string;
/**
* 自定义样式
*/
style?: React.CSSProperties;
/**
* 内容
*/
children?: React.ReactNode;
/**
* 是否禁用按钮
* @default false
*/
disabled?: boolean;
/**
* 按钮尺寸
* @default medium
*/
size?: 'small' | 'medium' | 'large';
}
const Button: React.FC<ButtonProps> = (props) => {
const {
children,
className,
style,
disabled = false,
size = 'medium',
...buttonProps
} = props;
return (
<button
className={classNames(
'i-button',
`i-button--size-${size}`,
className,
)}
style={{ ...style }}
disabled={disabled}
{...buttonProps}
>
{children}
</button>
);
};
Button.displayName = 'Button';
export default Button;
// 使用
<Button type="primary">按钮</Button>
<Button disabled>按钮</Button>
<Button loading={true}>按钮</Button>
<Button name={getName()}>按钮</Button>
七、Emit
- 小程序
- Vue
- React
// button.wxml
<button
class="i-button i-button--size-{{size}} custom-class"
style="{{customStyle}}"
bindtap="handleClick"
disabled="{{disabled}}"
>
<slot></slot>
</button>
// button.js
Component({
externalClasses: ['custom-class'],
properties: {
disabled: {
type: Boolean,
value: false,
},
size: {
type: String,
value: 'medium',
},
customStyle: {
type: String,
value: '',
},
},
methods: {
handleClick(e) {
this.triggerEvent('click', e);
},
},
});
// button.json
{
"component": true,
"usingComponents": {}
}
// 使用
<view class="container">
<i-button
custom-class="my-custom-class"
size="large"
bind:click="handleButtonClick"
>
点击我
</i-button>
</view>
<template>
<button
:class="['i-button', `i-button--size-${size}`]"
@click="(e) => emit('click', e)"
>
<slot />
</button>
</template>
<script setup lang="ts">
interface ButtonProps {
/**
* 是否禁用按钮
* @default false
*/
disabled?: boolean
/**
* 按钮尺寸
* @default medium
*/
size?: 'small' | 'medium' | 'large'
}
interface ButtonEmits {
/**
* 点击事件
*/
(type: 'click', e: MouseEvent): void
}
const {
disabled = false,
size = 'medium'
} = defineProps<ButtonProps>()
const emit = defineEmits<ButtonEmits>()
</script>
<style lang="scss">
@import './index.scss';
</style>
// 使用
<i-button type="primary">按钮</i-button>
<i-button disabled>按钮</i-button>
<i-button :loading="true">按钮</i-button>
<i-button :name={getName()}>按钮</i-button>
<i-button @click="handleAdd">按钮</i-button>
import React from 'react';
import classNames from 'classnames';
import './index.scss';
interface ButtonProps {
/**
* 类名
*/
className?: string;
/**
* 自定义样式
*/
style?: React.CSSProperties;
/**
* 内容
*/
children?: React.ReactNode;
/**
* 是否禁用按钮
* @default false
*/
disabled?: boolean;
/**
* 按钮尺寸
* @default medium
*/
size?: 'small' | 'medium' | 'large';
/**
* 点击事件
*/
onClick?: (e: React.MouseEvent) => void;
}
const Button: React.FC<ButtonProps> = (props) => {
const {
children,
className,
style,
disabled = false,
size = 'medium',
onClick,
...buttonProps
} = props;
return (
<button
className={classNames(
'i-button',
`i-button--size-${size}`,
className,
)}
style={{ ...style }}
disabled={disabled}
onClick={(e) => onClick?.(e)}
{...buttonProps}
>
{children}
</button>
);
};
Button.displayName = 'Button';
export default Button;
// 使用
<Button type="primary">按钮</Button>
<Button disabled>按钮</Button>
<Button loading={true}>按钮</Button>
<Button name={getName()}>按钮</Button>
<Button onClick={handleAdd}>按钮</Button>