这一节了解一下Vue3中的组件的属性和方法,在定义Vue组件时,属性和方法是重要的两部分,创建组件时,实现了其内部的data方法,这个方法返回一个对象,此对象中定义的数据会存储在组件实例中,并通过响应式的更新原理来影响页面渲染,简单总给如下:
API
- data 响应式数据
含义:组件内部状态数据源作用:存储变量,变化自动更新视图
javascript
<template>
<view>{{ msg }}</view>
</template>
<script setup>
import { ref } from 'vue'
const msg = ref('我是响应式数据')
</script>
- methods 方法
含义:组件业务函数作用:处理事件、逻辑、操作数据
javascript
<template>
<button @click="sayHi">点击</button>
</template>
<script setup>
const sayHi = () => uni.showToast({ title: 'Hi' })
</script>
- computed 计算属性
含义:根据依赖自动计算结果,带缓存作用:派生数据、过滤、格式化
javascript
<template>
<view>{{ fullName }}</view>
</template>
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('张')
const lastName = ref('三')
const fullName = computed(() => firstName.value + lastName.value)
</script>
- computed 带 set
含义:计算属性可读写作用:赋值时自动反向修改源数据
javascript
<template>
<view>{{ fullName }}</view>
<button @click="fullName = '李四'">改值</button>
</template>
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('张')
const lastName = ref('三')
const fullName = computed({
get: () => firstName.value + lastName.value,
set: (val) => (firstName.value = val)
})
</script>
- watch 侦听器
含义:监听数据变化作用:数据变化时执行异步 / 复杂逻辑
javascript
<template>
<input v-model="val" placeholder="输入测试" />
</template>
<script setup>
import { ref, watch } from 'vue'
const val = ref('')
watch(val, (newVal) => {
console.log('变化了:', newVal)
})
</script>
- watch 深度监听
含义:监听对象 / 数组内部变化作用:对象属性改变也能监听到
javascript
<script setup>
import { ref, watch } from 'vue'
const user = ref({ name: '小明' })
watch(
() => user.value,
() => console.log('对象变了'),
{ deep: true }
)
</script>
- watchEffect 自动侦听
含义:自动收集依赖,不用指定监听目标作用:简化监听逻辑
javascript
<script setup>
import { ref, watchEffect } from 'vue'
const count = ref(0)
watchEffect(() => console.log(count.value))
</script>
- v-model 双向绑定
含义:数据 ↔ 视图自动同步作用:快速处理输入框、单选、复选
javascript
<template>
<input v-model="msg" />
<view>{{ msg }}</view>
</template>
<script setup>
import { ref } from 'vue'
const msg = ref('')
</script>
- v-model.trim 去空格
含义:自动去掉首尾空格作用:净化输入内容
javascript
<input v-model.trim="msg" />
- v-model.lazy 失焦同步
含义:输入框失去焦点才更新数据作用:减少频繁更新
javascript
<input v-model.lazy="msg" />
- v-model.number 转数字
含义:输入内容自动转为数字作用:处理数字输入
javascript
<input v-model.number="num" type="text" />
- 单选框 v-model
含义:一组单选互斥作用:性别、状态选择
javascript
<template>
<radio-group v-model="gender">
<radio value="男">男</radio>
<radio value="女">女</radio>
</radio-group>
</template>
<script setup>
const gender = ref('男')
</script>
- 复选框 v-model
含义:多选绑定数组作用:兴趣、爱好、多选项
javascript
<template>
<checkbox-group v-model="hobbies">
<checkbox value="篮球">篮球</checkbox>
<checkbox value="音乐">音乐</checkbox>
</checkbox-group>
</template>
<script setup>
const hobbies = ref([])
</script>
- :class 对象绑定
含义:按条件添加样式作用:高亮、选中、禁用状态
javascript
<view :class="{ active: isActive }">文字</view>
<script setup>
const isActive = ref(true)
</script>
<style>.active{ color: red; }</style>
- :class 数组绑定
含义:同时应用多个样式作用:组合样式
javascript
<view :class="[class1, class2]">内容</view>
<script setup>
const class1 = 'text-red'
const class2 = 'font-bold'
</script>
- :style 内联样式
含义:动态设置 CSS作用:颜色、大小、位置实时变化
javascript
<view :style="{ color: textColor }">文字颜色</view>
<script setup>
const textColor = ref('blue')
</script>
- 函数节流(点击防抖)
含义:防止重复点击 / 重复提交作用:按钮防重复
javascript
<template>
<button @click="submit" :disabled="isLock">提交</button>
</template>
<script setup>
import { ref } from 'vue'
const isLock = ref(false)
const submit = () => {
if (isLock.value) return
isLock.value = true
setTimeout(() => (isLock.value = false), 1000)
}
</script>
栗子:
javascript
<template>
<view class="container">
<view>{{ msg }}</view>
<button @click="changeMsg">改文字</button>
<input v-model.trim="username" placeholder="用户名" />
<view>长度:{{ usernameLen }}</view>
<button
@click="submit"
:class="{ disabled: !canSubmit }"
:disabled="isLock"
>
提交
</button>
</view>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
const msg = ref('Demo')
const username = ref('')
const isLock = ref(false)
const changeMsg = () => (msg.value = '已修改')
const usernameLen = computed(() => username.value.length)
watch(username, (v) => console.log('输入:', v))
const canSubmit = computed(() => username.value.length >= 2)
const submit = () => {
if (isLock.value) return
isLock.value = true
uni.showToast({ title: '提交成功' })
setTimeout(() => (isLock.value = false), 1000)
}
</script>
<style scoped>
.container { padding: 30rpx; }
button { margin-top: 20rpx; }
.disabled { background: #ccc; }
</style>
javascript
<template>
<view class="login-page">
<view class="title">用户登录</view>
<view class="form-item">
<text>账号</text>
<input
v-model.trim="username"
class="input"
placeholder="请输入账号"
/>
<view class="tip" :style="usernameTipStyle">{{ usernameTip }}</view>
</view>
<view class="form-item">
<text>密码</text>
<input
v-model="password"
class="input"
password
placeholder="请输入密码"
/>
</view>
<view class="form-item check-row">
<checkbox v-model="rememberPwd" />
<text>记住密码</text>
</view>
<button
@click="handleLogin"
class="login-btn"
:class="{ disabled: !canLogin }"
:disabled="!canLogin || isLock"
>
{{ isLock ? '登录中...' : '登录' }}
</button>
</view>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
const username = ref('')
const password = ref('')
const rememberPwd = ref(false)
const isLock = ref(false)
const canLogin = computed(() => {
return username.value.length >= 3 && password.value.length >= 6
})
const usernameTip = computed(() => {
if (username.value.length === 0) return '请输入账号'
if (username.value.length < 3) return '账号至少3位'
return '账号格式正确'
})
const usernameTipStyle = computed(() => {
return username.value.length >= 3 ? 'color:green' : 'color:red'
})
watch(
() => password.value,
(newVal) => {
if (newVal.length > 0 && newVal.length < 6) {
console.log('密码长度不足6位')
}
}
)
const handleLogin = () => {
if (isLock.value) return
isLock.value = true
setTimeout(() => {
uni.showToast({
title: '登录成功',
icon: 'success'
})
console.log('登录数据:', {
username: username.value,
password: password.value,
rememberPwd: rememberPwd.value
})
isLock.value = false
}, 1500)
}
</script>
<style scoped>
.login-page {
padding: 60rpx 40rpx;
background: #fff;
min-height: 100vh;
}
.title {
font-size: 44rpx;
font-weight: bold;
text-align: center;
margin-bottom: 60rpx;
}
.form-item {
margin-bottom: 30rpx;
}
.form-item text {
font-size: 28rpx;
margin-bottom: 10rpx;
display: block;
}
.input {
border: 1rpx solid #eee;
border-radius: 10rpx;
padding: 22rpx;
font-size: 28rpx;
}
.tip {
font-size: 24rpx;
margin-top: 8rpx;
}
.check-row {
display: flex;
align-items: center;
gap: 10rpx;
}
.login-btn {
background: #42b983;
color: #fff;
border-radius: 10rpx;
margin-top: 50rpx;
}
.login-btn.disabled {
background: #ccc;
}
</style>