鸿蒙OSUniApp 实现的表单验证与提交功能#三方框架 #Uniapp

news2025/5/18 18:07:25

UniApp 实现的表单验证与提交功能

前言

在移动端应用开发中,表单是用户与应用交互的重要媒介。一个好的表单不仅布局合理、使用方便,还应该具备完善的验证与提交功能,以确保用户输入的数据准确无误。本文将分享如何在 UniApp 中实现表单验证与提交功能,帮助你构建更加健壮的表单系统。

作为一个经常与表单打交道的开发者,我发现很多初学者往往忽视了表单验证的重要性,或者实现方式不够优雅。通过本文,希望能为你提供一些关于 UniApp 表单处理的实用技巧和最佳实践。

为什么需要表单验证?

想象一下,如果没有表单验证,用户可能会提交不完整或格式错误的数据:

  • 手机号码少输一位或输入了字母
  • 密码太简单,不符合安全要求
  • 重要字段被遗漏
  • 日期格式错误
  • 上传的图片尺寸过大或格式不支持

这些问题不仅会导致后端数据处理错误,还会影响用户体验。因此,前端表单验证显得尤为重要。

UniApp 表单验证的实现方式

在 UniApp 中,有多种方式可以实现表单验证:

  1. 使用原生方法自行实现
  2. 使用第三方验证库(如 async-validator)
  3. 结合 uView 等 UI 框架使用内置验证功能

下面我们主要讨论前两种方式的实现。

方式一:自行实现表单验证

自行实现的优点是灵活、无需引入额外依赖,但需要自己编写各种验证规则和处理逻辑。

基本思路:
  1. 定义表单数据模型
  2. 编写验证规则函数
  3. 在提交前调用验证函数
  4. 根据验证结果决定是否提交

让我们看一个简单的注册表单验证示例:

export default {
  data() {
    return {
      // 表单数据
      form: {
        username: '',
        password: '',
        confirmPassword: '',
        mobile: '',
        email: '',
        agree: false
      },
      // 错误信息
      errors: {
        username: '',
        password: '',
        confirmPassword: '',
        mobile: '',
        email: '',
        agree: ''
      }
    }
  },
  methods: {
    // 验证用户名
    validateUsername() {
      if (!this.form.username) {
        this.errors.username = '用户名不能为空';
        return false;
      }
      if (this.form.username.length < 3 || this.form.username.length > 20) {
        this.errors.username = '用户名长度应为3-20个字符';
        return false;
      }
      this.errors.username = '';
      return true;
    },
    
    // 验证密码
    validatePassword() {
      if (!this.form.password) {
        this.errors.password = '密码不能为空';
        return false;
      }
      if (this.form.password.length < 6) {
        this.errors.password = '密码长度不能少于6个字符';
        return false;
      }
      // 包含数字和字母的正则表达式
      const passwordPattern = /^(?=.*[0-9])(?=.*[a-zA-Z]).{6,}$/;
      if (!passwordPattern.test(this.form.password)) {
        this.errors.password = '密码必须包含数字和字母';
        return false;
      }
      this.errors.password = '';
      return true;
    },
    
    // 验证确认密码
    validateConfirmPassword() {
      if (!this.form.confirmPassword) {
        this.errors.confirmPassword = '请确认密码';
        return false;
      }
      if (this.form.confirmPassword !== this.form.password) {
        this.errors.confirmPassword = '两次输入的密码不一致';
        return false;
      }
      this.errors.confirmPassword = '';
      return true;
    },
    
    // 验证手机号
    validateMobile() {
      if (!this.form.mobile) {
        this.errors.mobile = '手机号不能为空';
        return false;
      }
      // 中国大陆手机号正则表达式
      const mobilePattern = /^1[3-9]\d{9}$/;
      if (!mobilePattern.test(this.form.mobile)) {
        this.errors.mobile = '请输入有效的手机号码';
        return false;
      }
      this.errors.mobile = '';
      return true;
    },
    
    // 验证邮箱
    validateEmail() {
      if (!this.form.email) {
        this.errors.email = '邮箱不能为空';
        return false;
      }
      // 邮箱正则表达式
      const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
      if (!emailPattern.test(this.form.email)) {
        this.errors.email = '请输入有效的邮箱地址';
        return false;
      }
      this.errors.email = '';
      return true;
    },
    
    // 验证用户协议
    validateAgree() {
      if (!this.form.agree) {
        this.errors.agree = '请同意用户协议';
        return false;
      }
      this.errors.agree = '';
      return true;
    },
    
    // 验证所有字段
    validateForm() {
      const usernameValid = this.validateUsername();
      const passwordValid = this.validatePassword();
      const confirmPasswordValid = this.validateConfirmPassword();
      const mobileValid = this.validateMobile();
      const emailValid = this.validateEmail();
      const agreeValid = this.validateAgree();
      
      return usernameValid && passwordValid && confirmPasswordValid 
        && mobileValid && emailValid && agreeValid;
    },
    
    // 提交表单
    submitForm() {
      // 先清空所有错误信息
      for (let key in this.errors) {
        this.errors[key] = '';
      }
      
      // 验证表单
      if (!this.validateForm()) {
        uni.showToast({
          title: '请正确填写表单信息',
          icon: 'none'
        });
        return;
      }
      
      // 验证通过,可以进行提交操作
      uni.showLoading({
        title: '提交中...'
      });
      
      // 模拟提交请求
      setTimeout(() => {
        uni.hideLoading();
        uni.showToast({
          title: '注册成功',
          icon: 'success'
        });
        
        // 重置表单或跳转页面
        // this.resetForm();
        // uni.navigateTo({ url: '/pages/login/login' });
      }, 1500);
    },
    
    // 重置表单
    resetForm() {
      this.form = {
        username: '',
        password: '',
        confirmPassword: '',
        mobile: '',
        email: '',
        agree: false
      };
      for (let key in this.errors) {
        this.errors[key] = '';
      }
    }
  }
}

对应的模板部分可以这样编写:

<template>
  <view class="register-form">
    <view class="form-item">
      <text class="label">用户名</text>
      <input class="input" v-model="form.username" placeholder="请输入用户名" @blur="validateUsername" />
      <text v-if="errors.username" class="error-tip">{{ errors.username }}</text>
    </view>
    
    <view class="form-item">
      <text class="label">密码</text>
      <input class="input" v-model="form.password" type="password" placeholder="请输入密码" @blur="validatePassword" />
      <text v-if="errors.password" class="error-tip">{{ errors.password }}</text>
    </view>
    
    <view class="form-item">
      <text class="label">确认密码</text>
      <input class="input" v-model="form.confirmPassword" type="password" placeholder="请再次输入密码" @blur="validateConfirmPassword" />
      <text v-if="errors.confirmPassword" class="error-tip">{{ errors.confirmPassword }}</text>
    </view>
    
    <view class="form-item">
      <text class="label">手机号</text>
      <input class="input" v-model="form.mobile" type="number" placeholder="请输入手机号" @blur="validateMobile" />
      <text v-if="errors.mobile" class="error-tip">{{ errors.mobile }}</text>
    </view>
    
    <view class="form-item">
      <text class="label">邮箱</text>
      <input class="input" v-model="form.email" placeholder="请输入邮箱" @blur="validateEmail" />
      <text v-if="errors.email" class="error-tip">{{ errors.email }}</text>
    </view>
    
    <view class="form-item checkbox-item">
      <checkbox v-model="form.agree" />
      <text class="agreement-text" @click="form.agree = !form.agree">我已阅读并同意《用户协议》</text>
      <text v-if="errors.agree" class="error-tip">{{ errors.agree }}</text>
    </view>
    
    <button class="submit-btn" type="primary" @click="submitForm">立即注册</button>
  </view>
</template>

并添加一些基本样式:

<style scoped>
.register-form {
  padding: 30rpx;
}

.form-item {
  margin-bottom: 40rpx;
  position: relative;
}

.label {
  display: block;
  margin-bottom: 10rpx;
  font-size: 28rpx;
  color: #333;
}

.input {
  width: 100%;
  height: 80rpx;
  border: 1rpx solid #dcdfe6;
  border-radius: 8rpx;
  padding: 0 20rpx;
  box-sizing: border-box;
  font-size: 28rpx;
}

.error-tip {
  position: absolute;
  left: 0;
  bottom: -36rpx;
  font-size: 24rpx;
  color: #f56c6c;
}

.checkbox-item {
  display: flex;
  align-items: center;
}

.agreement-text {
  font-size: 26rpx;
  margin-left: 10rpx;
}

.submit-btn {
  margin-top: 60rpx;
}
</style>

方式二:使用 async-validator 库

对于复杂的验证需求,使用成熟的验证库会更加便捷。async-validator 是一个流行的表单验证库,支持丰富的验证规则和自定义验证功能。

首先,安装依赖:

npm install async-validator --save

然后,在组件中使用:

import Schema from 'async-validator';

export default {
  data() {
    return {
      // 表单数据
      form: {
        username: '',
        password: '',
        confirmPassword: '',
        mobile: '',
        email: '',
        agree: false
      },
      // 错误信息
      errors: {}
    }
  },
  computed: {
    // 定义验证规则
    rules() {
      return {
        username: [
          { required: true, message: '用户名不能为空' },
          { min: 3, max: 20, message: '用户名长度应为3-20个字符' }
        ],
        password: [
          { required: true, message: '密码不能为空' },
          { min: 6, message: '密码长度不能少于6个字符' },
          { 
            pattern: /^(?=.*[0-9])(?=.*[a-zA-Z]).{6,}$/, 
            message: '密码必须包含数字和字母' 
          }
        ],
        confirmPassword: [
          { required: true, message: '请确认密码' },
          { 
            validator: (rule, value, callback) => {
              if (value !== this.form.password) {
                callback(new Error('两次输入的密码不一致'));
              } else {
                callback();
              }
            } 
          }
        ],
        mobile: [
          { required: true, message: '手机号不能为空' },
          { pattern: /^1[3-9]\d{9}$/, message: '请输入有效的手机号码' }
        ],
        email: [
          { required: true, message: '邮箱不能为空' },
          { type: 'email', message: '请输入有效的邮箱地址' }
        ],
        agree: [
          { 
            validator: (rule, value, callback) => {
              if (!value) {
                callback(new Error('请同意用户协议'));
              } else {
                callback();
              }
            } 
          }
        ]
      };
    }
  },
  methods: {
    // 验证单个字段
    validateField(field) {
      const descriptor = {};
      descriptor[field] = this.rules[field];
      
      const validator = new Schema(descriptor);
      const source = {};
      source[field] = this.form[field];
      
      validator.validate(source, (errors) => {
        if (errors) {
          // 有错误
          this.$set(this.errors, field, errors[0].message);
        } else {
          // 没有错误
          this.$set(this.errors, field, '');
        }
      });
    },
    
    // 验证所有字段
    validateForm() {
      return new Promise((resolve, reject) => {
        const validator = new Schema(this.rules);
        
        validator.validate(this.form, (errors) => {
          if (errors) {
            // 有错误
            const errorObj = {};
            errors.forEach(error => {
              errorObj[error.field] = error.message;
            });
            this.errors = errorObj;
            resolve(false);
          } else {
            // 验证通过
            this.errors = {};
            resolve(true);
          }
        });
      });
    },
    
    // 提交表单
    async submitForm() {
      const valid = await this.validateForm();
      
      if (!valid) {
        uni.showToast({
          title: '请正确填写表单信息',
          icon: 'none'
        });
        return;
      }
      
      // 验证通过,可以进行提交操作
      uni.showLoading({
        title: '提交中...'
      });
      
      // 模拟提交请求
      setTimeout(() => {
        uni.hideLoading();
        uni.showToast({
          title: '注册成功',
          icon: 'success'
        });
        
        // 重置表单或跳转页面
        // this.resetForm();
        // uni.navigateTo({ url: '/pages/login/login' });
      }, 1500);
    },
    
    // 重置表单
    resetForm() {
      this.form = {
        username: '',
        password: '',
        confirmPassword: '',
        mobile: '',
        email: '',
        agree: false
      };
      this.errors = {};
    }
  }
}

模板部分可以与前面的例子类似,只需要修改验证方法的调用:

<input class="input" v-model="form.username" placeholder="请输入用户名" @blur="validateField('username')" />

表单提交功能的实现

表单验证通过后,我们需要将数据提交到服务器。在 UniApp 中,可以使用 uni.request() 方法发送网络请求。

下面是一个完整的表单提交示例:

// 提交表单
async submitForm() {
  const valid = await this.validateForm();
  
  if (!valid) {
    uni.showToast({
      title: '请正确填写表单信息',
      icon: 'none'
    });
    return;
  }
  
  // 显示加载提示
  uni.showLoading({
    title: '提交中...'
  });
  
  try {
    // 发送请求
    const res = await uni.request({
      url: 'https://api.example.com/register',
      method: 'POST',
      data: this.form,
      header: {
        'content-type': 'application/json'
      }
    });
    
    // 请求成功
    if (res.statusCode === 200 && res.data.code === 0) {
      uni.hideLoading();
      uni.showToast({
        title: '注册成功',
        icon: 'success'
      });
      
      // 存储登录信息
      uni.setStorageSync('token', res.data.data.token);
      uni.setStorageSync('userInfo', res.data.data.userInfo);
      
      // 跳转到首页
      setTimeout(() => {
        uni.switchTab({
          url: '/pages/index/index'
        });
      }, 1500);
    } else {
      throw new Error(res.data.message || '注册失败');
    }
  } catch (error) {
    uni.hideLoading();
    uni.showToast({
      title: error.message || '网络错误,请稍后重试',
      icon: 'none'
    });
  }
}

实战案例:会员信息编辑表单

下面是一个完整的会员信息编辑表单案例,综合了表单验证和提交功能:

<template>
  <view class="profile-form">
    <view class="form-header">
      <view class="avatar-wrapper">
        <image class="avatar" :src="form.avatar || '/static/default-avatar.png'" @click="chooseAvatar"></image>
        <text class="edit-hint">点击修改头像</text>
      </view>
    </view>
    
    <view class="form-content">
      <view class="form-item">
        <text class="label">姓名</text>
        <input class="input" v-model="form.name" placeholder="请输入您的姓名" @blur="validateField('name')" />
        <text v-if="errors.name" class="error-tip">{{ errors.name }}</text>
      </view>
      
      <view class="form-item">
        <text class="label">性别</text>
        <view class="radio-group">
          <view class="radio-item" @click="form.gender = 1">
            <view class="radio-box" :class="{ 'checked': form.gender === 1 }"></view>
            <text class="radio-label">男</text>
          </view>
          <view class="radio-item" @click="form.gender = 2">
            <view class="radio-box" :class="{ 'checked': form.gender === 2 }"></view>
            <text class="radio-label">女</text>
          </view>
        </view>
      </view>
      
      <view class="form-item">
        <text class="label">手机号</text>
        <input class="input" v-model="form.mobile" type="number" placeholder="请输入手机号" @blur="validateField('mobile')" />
        <text v-if="errors.mobile" class="error-tip">{{ errors.mobile }}</text>
      </view>
      
      <view class="form-item">
        <text class="label">邮箱</text>
        <input class="input" v-model="form.email" placeholder="请输入邮箱" @blur="validateField('email')" />
        <text v-if="errors.email" class="error-tip">{{ errors.email }}</text>
      </view>
      
      <view class="form-item">
        <text class="label">生日</text>
        <picker mode="date" :value="form.birthday" @change="onBirthdayChange">
          <view class="picker-box">
            <text class="picker-text">{{ form.birthday || '请选择出生日期' }}</text>
            <text class="picker-arrow">></text>
          </view>
        </picker>
      </view>
      
      <view class="form-item">
        <text class="label">地址</text>
        <textarea class="textarea" v-model="form.address" placeholder="请输入您的详细地址" @blur="validateField('address')" />
        <text v-if="errors.address" class="error-tip">{{ errors.address }}</text>
      </view>
      
      <view class="form-item">
        <text class="label">个人简介</text>
        <textarea class="textarea" v-model="form.bio" placeholder="介绍一下自己吧(选填)" />
      </view>
    </view>
    
    <button class="submit-btn" type="primary" @click="submitForm">保存修改</button>
  </view>
</template>

<script>
import Schema from 'async-validator';

export default {
  data() {
    return {
      // 表单数据
      form: {
        avatar: '',
        name: '',
        gender: 1, // 1-男,2-女
        mobile: '',
        email: '',
        birthday: '',
        address: '',
        bio: ''
      },
      // 错误信息
      errors: {}
    }
  },
  computed: {
    // 定义验证规则
    rules() {
      return {
        name: [
          { required: true, message: '姓名不能为空' },
          { max: 20, message: '姓名长度不能超过20个字符' }
        ],
        mobile: [
          { required: true, message: '手机号不能为空' },
          { pattern: /^1[3-9]\d{9}$/, message: '请输入有效的手机号码' }
        ],
        email: [
          { required: true, message: '邮箱不能为空' },
          { type: 'email', message: '请输入有效的邮箱地址' }
        ],
        address: [
          { required: true, message: '地址不能为空' },
          { max: 100, message: '地址长度不能超过100个字符' }
        ]
      };
    }
  },
  onLoad() {
    // 获取用户信息(示例数据)
    const userInfo = {
      avatar: '/static/avatar.png',
      name: '张三',
      gender: 1,
      mobile: '13800138000',
      email: 'zhangsan@example.com',
      birthday: '1990-01-01',
      address: '北京市朝阳区某某街道某某小区',
      bio: '热爱生活,热爱编程。'
    };
    
    // 填充表单
    this.form = { ...userInfo };
  },
  methods: {
    // 选择头像
    chooseAvatar() {
      uni.chooseImage({
        count: 1,
        sizeType: ['compressed'],
        sourceType: ['album', 'camera'],
        success: (res) => {
          const tempFilePaths = res.tempFilePaths;
          this.form.avatar = tempFilePaths[0];
          
          // 实际场景中应该先上传图片,再获取图片的URL
          this.uploadAvatar(tempFilePaths[0]);
        }
      });
    },
    
    // 上传头像
    uploadAvatar(filePath) {
      uni.showLoading({
        title: '上传中...'
      });
      
      // 模拟上传
      setTimeout(() => {
        uni.hideLoading();
        uni.showToast({
          title: '头像上传成功',
          icon: 'success'
        });
        
        // 实际场景中,这里应该返回服务器的图片URL
        // this.form.avatar = res.data.url;
      }, 1500);
    },
    
    // 生日改变
    onBirthdayChange(e) {
      this.form.birthday = e.detail.value;
    },
    
    // 验证单个字段
    validateField(field) {
      if (!this.rules[field]) return;
      
      const descriptor = {};
      descriptor[field] = this.rules[field];
      
      const validator = new Schema(descriptor);
      const source = {};
      source[field] = this.form[field];
      
      validator.validate(source, (errors) => {
        if (errors) {
          // 有错误
          this.$set(this.errors, field, errors[0].message);
        } else {
          // 没有错误
          this.$set(this.errors, field, '');
        }
      });
    },
    
    // 验证所有字段
    validateForm() {
      return new Promise((resolve, reject) => {
        const validator = new Schema(this.rules);
        
        validator.validate(this.form, (errors) => {
          if (errors) {
            // 有错误
            const errorObj = {};
            errors.forEach(error => {
              errorObj[error.field] = error.message;
            });
            this.errors = errorObj;
            resolve(false);
          } else {
            // 验证通过
            this.errors = {};
            resolve(true);
          }
        });
      });
    },
    
    // 提交表单
    async submitForm() {
      const valid = await this.validateForm();
      
      if (!valid) {
        uni.showToast({
          title: '请正确填写表单信息',
          icon: 'none'
        });
        return;
      }
      
      // 显示加载提示
      uni.showLoading({
        title: '保存中...'
      });
      
      // 模拟提交请求
      setTimeout(() => {
        uni.hideLoading();
        uni.showToast({
          title: '保存成功',
          icon: 'success'
        });
        
        // 返回上一页
        setTimeout(() => {
          uni.navigateBack();
        }, 1500);
      }, 1500);
      
      /* 实际场景中的提交代码
      try {
        const res = await uni.request({
          url: 'https://api.example.com/update-profile',
          method: 'POST',
          data: this.form,
          header: {
            'content-type': 'application/json',
            'Authorization': `Bearer ${uni.getStorageSync('token')}`
          }
        });
        
        if (res.statusCode === 200 && res.data.code === 0) {
          uni.hideLoading();
          uni.showToast({
            title: '保存成功',
            icon: 'success'
          });
          
          // 更新本地存储的用户信息
          uni.setStorageSync('userInfo', res.data.data.userInfo);
          
          // 返回上一页
          setTimeout(() => {
            uni.navigateBack();
          }, 1500);
        } else {
          throw new Error(res.data.message || '保存失败');
        }
      } catch (error) {
        uni.hideLoading();
        uni.showToast({
          title: error.message || '网络错误,请稍后重试',
          icon: 'none'
        });
      }
      */
    }
  }
}
</script>

<style scoped>
.profile-form {
  padding: 30rpx;
}

.form-header {
  display: flex;
  justify-content: center;
  margin-bottom: 50rpx;
}

.avatar-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.avatar {
  width: 150rpx;
  height: 150rpx;
  border-radius: 50%;
  margin-bottom: 10rpx;
}

.edit-hint {
  font-size: 24rpx;
  color: #666;
}

.form-content {
  margin-bottom: 40rpx;
}

.form-item {
  margin-bottom: 40rpx;
  position: relative;
}

.label {
  display: block;
  margin-bottom: 10rpx;
  font-size: 28rpx;
  color: #333;
}

.input, .textarea, .picker-box {
  width: 100%;
  border: 1rpx solid #dcdfe6;
  border-radius: 8rpx;
  padding: 0 20rpx;
  box-sizing: border-box;
  font-size: 28rpx;
}

.input, .picker-box {
  height: 80rpx;
  line-height: 80rpx;
}

.textarea {
  height: 160rpx;
  padding: 20rpx;
  line-height: 1.5;
}

.picker-box {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.picker-text {
  color: #333;
}

.picker-arrow {
  color: #999;
  transform: rotate(90deg);
}

.radio-group {
  display: flex;
  margin-top: 10rpx;
}

.radio-item {
  display: flex;
  align-items: center;
  margin-right: 50rpx;
}

.radio-box {
  width: 40rpx;
  height: 40rpx;
  border: 2rpx solid #dcdfe6;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  box-sizing: border-box;
  position: relative;
}

.radio-box.checked {
  border-color: #2979ff;
}

.radio-box.checked:after {
  content: '';
  width: 20rpx;
  height: 20rpx;
  border-radius: 50%;
  background-color: #2979ff;
  position: absolute;
}

.radio-label {
  margin-left: 10rpx;
  font-size: 28rpx;
}

.error-tip {
  position: absolute;
  left: 0;
  bottom: -36rpx;
  font-size: 24rpx;
  color: #f56c6c;
}

.submit-btn {
  margin-top: 60rpx;
}
</style>

表单验证的最佳实践

  1. 实时验证与提交验证结合:在输入框失去焦点时进行单个字段验证,在表单提交时进行全表单验证
  2. 友好的错误提示:错误信息应该清晰明了,位置合适
  3. 良好的用户体验:添加适当的过渡效果,不要让错误提示突兀出现
  4. 避免重复验证:已验证过且符合要求的字段无需重复验证
  5. 表单防抖:防止用户频繁点击提交按钮
  6. 状态保持:表单提交失败后不要清空用户输入
  7. 进度提示:使用加载提示,让用户知道表单正在提交

总结

本文介绍了在 UniApp 中实现表单验证与提交功能的多种方式,包括自定义验证和使用第三方库验证。我们通过实例详细讲解了各种验证规则的编写,以及表单提交的完整流程。

表单验证看似简单,但实际上涉及众多细节,一个设计良好的表单验证系统能极大提升用户体验。希望本文对你在 UniApp 中开发表单功能有所帮助。

在实际项目中,你可能需要根据业务需求进行更多定制化的开发,例如添加更复杂的验证规则、优化表单的交互效果、处理更多的表单场景等。不论如何变化,本文提供的基本思路和方法都是适用的。

进一步思考

  • 如何处理更复杂的表单依赖验证?(例如,当选择A选项时,B字段必填)
  • 如何处理文件上传类型的表单字段?
  • 如何优化大型复杂表单的性能?
  • 如何实现多步骤表单?

这些都是表单开发中的进阶话题,欢迎在实践中探索更多解决方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2378674.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在 Windows 11 或 10 的 CMD 中检查固件

检查 Windows 11 或 10 中现有设备的硬件固件版本,可以帮助用户安装和更新准确的驱动程序,进行故障排除活动,确保兼容性以及维护系统性能。因此,在本教程中,我们将讨论如何在命令提示符(CMD)中使用一些命令查找 Windows 服务器或桌面中硬件固件版本的方法。由于本教程将…

进阶-数据结构部分:3、常用查找算法

飞书文档https://x509p6c8to.feishu.cn/wiki/LRdnwfhNgihKeXka7DfcGuRPnZt 顺序查找 查找算法是指&#xff1a;从一些数据之中&#xff0c;找到一个特殊的数据的实现方法。查找算法与遍历有极高的相似性&#xff0c;唯一的不同就是查找算法可能并不一定会将每一个数据都进行访…

基于QT和FFmpeg实现自己的视频播放器FFMediaPlayer(一)——项目总览

在音视频开发的学习过程中&#xff0c;开发一款视频播放器是FFmpeg进阶的最好实战方法。本文将基于 QT 和 FFmpeg 着手实现自定义视频播放器 FFMediaPlayer&#xff0c;作为系列文章的开篇&#xff0c;我们先来整体了解项目的设计思路、架构与配置。 一、软件设计五大原则​ …

【HCIA】浮动路由

前言 我们通常会在出口路由器配置静态路由去规定流量进入互联网默认应该去往哪里。那么&#xff0c;如果有两个运营商的路由器都能为我们提供上网服务&#xff0c;我们应该如何配置默认路由呢&#xff1f;浮动路由又是怎么一回事呢&#xff1f; 文章目录 前言1. 网络拓扑图2. …

使用instance着色

本节我们学习使用instance着色器进行着色 //拾取var handler new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);handler.setInputAction(function(movement){console.log(movement);var pickedObject viewer.scene.pick(movement.position);if(Cesium.defined(picke…

【NLP 72、Prompt、Agent、MCP、function calling】

命运把我们带到哪里&#xff0c;就是哪里 —— 25.5.13 一、Prompt 1.User Prompt 用户提示词 当我们与大模型进行对话时&#xff0c;我们向大模型发送的消息&#xff0c;称作User Prompt&#xff0c;也就是用户提示词&#xff0c;一般就是我们提出的问题或者想说的话 但是我们…

Mysql数据库之集群进阶

一、日志管理 5.7版本自定义路径时的文件需要自己提前创建好文件&#xff0c;不会自动创建&#xff0c;否则启动mysql会报错 错误日志 rpm包(yum) /var/log/mysql.log 默认错误日志 ###查询日志路径 [rootdb01 ~]# mysqladmin -uroot -pEgon123 variables | grep -w log_e…

临床决策支持系统的提示工程优化路径深度解析

引言 随着人工智能技术在医疗领域的迅猛发展,临床决策支持系统(CDSS)正经历从传统规则引擎向智能提示工程的范式转变。在这一背景下,如何构建既符合循证医学原则又能适应个体化医疗需求的CDSS成为医学人工智能领域的核心挑战。本报告深入剖析了临床决策支持系统中提示工程的…

苹果新一代车载系统CarPlay Ultra来袭,全屏接管+ChatGPT助力,智能驾驶要“起飞”

AITOP100获悉&#xff0c;苹果又搞出大动作啦&#xff01;正式推出了新一代车载系统——CarPlay Ultra。这次&#xff0c;苹果可是下了狠功夫&#xff0c;把iPhone和汽车的所有显示屏深度整合到了一起&#xff0c;还首次把ChatGPT引入到了驾驶体验当中。这系统可不简单&#xf…

无线信道的噪声与干扰

目录 1. 无线信道(wireless channel)与电磁波 2.1 电磁波的传输(无线信道传输) 2.2 视线(line of sight)传播与天线高度 2. 信道的数学模型 2.1 调制信道模型 2.1.1 加性噪声/加性干扰 2.1.2 乘性噪声/乘性干扰 2.1.3 随参信道/恒参信道 2.2 编码信道模型 2.3 小结 …

MySQL 8.0 OCP 1Z0-908 101-110题

Q101.which two queries are examples of successful SQL injection attacks? A.SELECT id, name FROM backup_before WHERE name‘; DROP TABLE injection; --’; B. SELECT id, name FROM user WHERE id23 oR id32 OR 11; C. SELECT id, name FROM user WHERE user.id (SEL…

BBR 的 buffer 动力学观感

这周很忙&#xff0c;今天还加了一天班&#xff0c;但还是抽空实现了五一在安徽泾县山区喝着一壶酒写的 BBR ProbeRTT 的想法&#xff0c;没多少行代码&#xff0c;它真就消除了带宽锯齿&#xff0c;皮了个鞋&#x1f45e;&#xff0c;昨天我还在群里说了今天再说说 BBR 的&…

Spring之Bean的初始化 Bean的生命周期 全站式解析

目录 导图 步骤 第一步 实例化 第二步 属性赋值 第三步 初始化 aware 接口 BeanPostProcessor 接口 InitializingBean 和 init-method 第四步使用 第五步使用后销毁 描述一下 Bean 的 生命周期 导图 步骤 总体上可以分为五步 首先是 Bean 的实例化Bean 在进行实例…

FreeCAD源码分析: Transaction实现原理

本文阐述FreeCAD中Transaction的实现原理。 注1&#xff1a;限于研究水平&#xff0c;分析难免不当&#xff0c;欢迎批评指正。 注2&#xff1a;文章内容会不定期更新。 一、概念 Ref. from What is a Transaction? A transaction is a group of operations that have the f…

flutter缓存网络视频到本地,可离线观看

记录一下解决问题的过程&#xff0c;希望自己以后可以参考看看&#xff0c;解决更多的问题。 需求&#xff1a;flutter 缓存网络视频文件&#xff0c;可离线观看。 解决&#xff1a; 1&#xff0c;flutter APP视频播放组件调整&#xff1b; 2&#xff0c;找到视频播放组件&a…

Kotlin 中 infix 关键字的原理和使用场景

在 Kotlin 中&#xff0c;使用 infix 关键字修饰的函数称为中缀函数&#xff0c;使用是可以省略 . 和 ()&#xff0c;允许以更自然&#xff08;类似自然语言&#xff09;的语法调用函数&#xff0c;这种特性可以使代码更具可读性。 1 infix 的原理 中缀函数必须满足以下条件&…

c++从入门到精通(五)--异常处理,命名空间,多继承与虚继承

异常处理 栈展开过程&#xff1a; 栈展开过程沿着嵌套函数的调用链不断查找&#xff0c;直到找到了与异常匹配的catch子句为止&#xff1b;也可能一直没找到匹配的catch&#xff0c;则退出主函数后查找过程终止。栈展开过程中的对象被自动销毁。 在栈展开的过程中&#xff0c…

gcc/g++常用参数

1.介绍 gcc用于编译c语言&#xff0c;g用于编译c 源代码生成可执行文件过程&#xff0c;预处理-编译-汇编-链接。https://zhuanlan.zhihu.com/p/476697014 2.常用参数说明 2.1编译过程控制 参数作用-oOutput&#xff0c;指定输出名字-cCompile&#xff0c;编译源文件生成对…

nginx配置之负载均衡

版权声明&#xff1a;原创作品&#xff0c;请勿转载&#xff01; 1.实验环境准备 准备3台linux服务器&#xff08;ubuntu和centos均可&#xff0c;本文使用centos7.9&#xff09;&#xff0c;两台web和一台负载均衡服务器&#xff0c;均安装nginx服务 主机名IP软件lb0110.0.0…

去年开发一款鸿蒙Next Os的window工具箱

持拖载多个鸿蒙应用 批量签名安装 运行 http://dl.lozn.top/lozn/HarmonySignAndFileManagerTool_2024-11-26.zip 同类型安卓工具箱以及其他软件下载地址汇总 http://dl.lozn.top/lozn/ 怎么个玩法呢&#xff0c;比如要启动某app, 拖载识别到包名 点启动他能主动读取包名 然后…