从React Native,Flutter到小程序(五)基本控件

基本控件一般包含文本,按钮,图片,输入框,表单等。

React Native Text

import React, { useState } from "react";
import { Text, StyleSheet } from "react-native";

const TextInANest = () => {
  const [titleText, setTitleText] = useState("Bird's Nest");
  const bodyText = useState("This is not really a bird nest.");

  const onPressTitle = () => {
    setTitleText("Bird's Nest [pressed]");
  };

  return (
    <Text style={styles.baseText}>
      <Text style={styles.titleText} onPress={onPressTitle}>
        {titleText}
        {"\n"}
        {"\n"}
      </Text>
      <Text numberOfLines={5}>{bodyText}</Text>
    </Text>
  );
};

const styles = StyleSheet.create({
  baseText: {
    fontFamily: "Cochin"
  },
  titleText: {
    fontSize: 20,
    fontWeight: "bold"
  }
});

在上述代码中,我们使用了 React Native 提供的 Text 和 StyleSheet 组件,并使用 useState Hooks 来创建状态变量和更新方法。

我们将整个组件用基础样式 baseText 包裹,并对标题文本 titleText 应用特殊样式。当用户点击标题文本时,会调用 onPressTitle 方法来更新标题文本的内容。

最后,我们单独定义了两个样式规则:baseText 和 titleText,并使用 StyleSheet.create 方法创建 styles 对象来存储它们。

Flutter Text

创建了一个名为 TextInANest 的有状态组件,并将标题和正文文本保存在两个字符串变量 _titleText 和 _bodyText 中。通过调用 setState() 方法,我们可以更新 _titleText 变量并重新渲染组件。

import 'package:flutter/material.dart';

class TextInANest extends StatefulWidget {
  
  _TextInANestState createState() => _TextInANestState();
}

class _TextInANestState extends State<TextInANest> {
  // 初始化标题文本设置为 "Bird's Nest"
  // 定义一个保存标题文本的变量
  String _titleText = "Bird's Nest";

  // 初始化正文文本设置为 "This is not really a bird nest."
  // 定义一个保存正文文本的变量
  String _bodyText = "This is not really a bird nest.";

  // 当标题文本被点击时执行该方法,更新标题文本
  void _onPressTitle() {
    setState(() {
      _titleText = "Bird's Nest [pressed]";
    });
  }

  
  Widget build(BuildContext context) {
    return Text.rich(
      TextSpan(
        children: [
          // 将标题文本单独作为一个 Text 组件,并应用我定义的样式规则 titleTextStyle
          TextSpan(
            text: '$_titleText\n\n',
            style: titleTextStyle,
            recognizer: TapGestureRecognizer()..onTap = _onPressTitle,
          ),

          // 将正文文本单独作为一个 Text 组件,并应用我定义的样式规则 bodyTextStyle
          TextSpan(
            text: _bodyText,
            style: bodyTextStyle,
          ),
        ],
      ),
    );
  }
}

final titleTextStyle = TextStyle(
  // 设置字体
  fontFamily: 'Cochin',

  // 设置标题文本的样式属性
  color: Colors.red, // 标题字体颜色为红色
  fontSize: 20,
  fontWeight: FontWeight.bold,
);

final bodyTextStyle = TextStyle(
  // 设置字体
  fontFamily: 'Cochin',

  // 设置正文文本的样式属性
  color: Colors.blue, // 正文字体颜色为蓝色
  fontSize: 16,
);

在上述 Flutter 代码中,我们使用了 Text.rich 组件来实现不同样式的标题和正文文本。它接受一个 TextSpan 对象作为参数,该对象包含一组子节点,每个节点都可以应用自己的样式规则。

我们定义了 titleTextStyle 和 bodyTextStyle 来分别设置标题和正文组件的样式规则,并在 TextSpan 中使用它们的样式来应用样式规则。

注意,在这里,我们将标题文本与正文文本分别添加到单独的 TextSpan 中,以便我们可以为它们分别应用不同的样式规则,而不是将它们放在同一行中并使用相同的样式。同时,我们仍然使用手势检测器将点击事件添加到 _titleText 上并调用 _onPressTitle 方法。

微信小程序 Text

<rich-text class="baseText">
  <text class="titleText" bindtap="onPressTitle">{{ titleText }}</text>
  <text>{{ '\n\n' }}</text>
  <text>{{ bodyText }}</text>
</rich-text>
Page({
  data: {
    titleText: "Bird's Nest",
    bodyText: "This is not really a bird nest.",
  },

  onPressTitle() {
    this.setData({ titleText: "Bird's Nest [pressed]" });
  },
})
.baseText {
  font-family: 'Cochin', 'Arial';
}

.titleText {
  font-size: 20px;
  font-weight: bold;
  color: red;
}

React Native Button

import React from 'react';
import { StyleSheet, Button, View, SafeAreaView, Text, Alert } from 'react-native';
import Constants from 'expo-constants';

const Separator = () => {
  return <View style={styles.separator} />;
}

// 应用程序的主要组件
const App = () => {
  return (
    // 安全视图,确保显示不受操作系统或设备的限制。
    <SafeAreaView style={styles.container}>
      <View>
        <Text style={styles.title}>
           文本标题说明,该组件必须具有title和onPress参数。建议设置accessibilityLabel属性以帮助所有人同时使用您的应用程序。
        </Text>

        // 按钮节点,当用户点击该按钮时调用 onPress 函数
        <Button
          title="Press me" // 按钮上的文字
          onPress={() => Alert.alert('Simple Button pressed')} // 点击函数
        />
      </View>

      <Separator /> // 分隔线组件,用于界面结构规整

      <View>
        <Text style={styles.title}>
           将颜色适当地调整到每个平台上看起来标准的方式。在iOS平台上,可以使用color属性控制文本颜色;在Android平台上,color属性控制按钮的背景颜色。
        </Text>
        <Button
          title="Press me"
          color="#f194ff" // 设置按钮背景颜色(在 iOS 上调整文本颜色)
          onPress={() => Alert.alert('Button with adjusted color pressed')}
        />
      </View>

      <Separator />

      <View>
        <Text style={styles.title}>
          // 禁止与该组件的所有交互。
        </Text>
        <Button
          title="Press me"
          disabled // 按钮失效,用户无法点击
          onPress={() => Alert.alert('Cannot press this one')}
        />
      </View>

      <Separator />

      <View>
        <Text style={styles.title}>
           此布局策略允许标题定义按钮的宽度。
        </Text>

        // 将两个按钮在横向排列,并将它们左右分别放置。
        <View style={styles.fixToText}>
          <Button
            title="Left button"
            onPress={() => Alert.alert('Left button pressed')}
          />
          <Button
            title="Right button"
            onPress={() => Alert.alert('Right button pressed')}
          />
        </View>
      </View>
    </SafeAreaView> // 结束安全视图
  );
}

// 样式表
const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: Constants.statusBarHeight, // 顶部状态栏高度偏移量
    marginHorizontal: 16, // 容器水平边距
  },
  title: {
    textAlign: 'center', // 居中对齐文本
    marginVertical: 8, // 垂直方向外边距
  },
  fixToText: {
    flexDirection: 'row', // 行排布
    justifyContent: 'space-between', // 两端对齐
  },
  separator: {
    marginVertical: 8, // 垂直方向外边距
    borderBottomColor: '#737373', // 分隔线的下边缘颜色
    borderBottomWidth: StyleSheet.hairlineWidth, // 分隔线粗细:StyleSheet.hairlineWidth 表示继承自设备像素密度
  },
});

export default App; // 导出组件

Flutter Button

Flutter 中有几种不同类型的 Button(按钮)。以下是其中几种:

RaisedButton
RaisedButton 是一个带有阴影和可自定义背景颜色的 Material Design 风格按钮。它通常会引起用户的注意,因为它看起来像是浮在 UI 应用程序之上的一张纸片。

RaisedButton(
onPressed: () {},
child: Text(‘Raised Button’),
);
FlatButton
FlatButton 是没有边框但可以自定义背景和字体颜色的按钮。虽然它不能像 RaisedButton 那样提供一个实际的立体效果,但仍然可以让应用程序显得更加简洁明了。

FlatButton(
onPressed: () {},
child: Text(‘Flat Button’),
);
OutlineButton
OutlineButton 是一个有边框但没有填充颜色的按钮。它也可以自定义边框和字体颜色。

OutlineButton(
onPressed: () {},
child: Text(‘Outline Button’),
);
IconButton
IconButton 是一个图标按钮,它通常会出现在应用程序的工具栏、导航栏或 appbar 上。

IconButton(
icon: Icon(Icons.favorite),
onPressed: () {},
);
FloatingActionButton
FloatingActionButton 是一个悬浮按钮,它通常出现在应用程序的底部右侧,并且将最常用的操作集成到一个便捷的位置。

FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
);
以上是 Flutter 中常用的几种 Button 类型,它们各有特点,在不同场景下使用会有不错的效果。

例子

import 'package:flutter/material.dart';

class MyApp extends StatelessWidget { // 应用程序的根组件
  
  Widget build(BuildContext context) { // 使用build方法返回应用程序的主体部分
    return MaterialApp( // MaterialApp是基于Material Design设计体系的标签,作为整个应用的主要Wdiget,提供给顶级Navigator、Theme、标题等所有子组件使用。
      home: Scaffold( // 脚手架是一个方便实现常见应用程序布局模式的组件。包含AppBar、底部NavigationBar、FloatingActionButton和Drawer等常见布局组件,并管理这些子组件的位置。
        body: Container( // 容器是可以大小可定位的可视化元素。它可以包含很多小的Wdiget,并具有自己的样式、绘制优化以及布局特性。
          margin: EdgeInsets.symmetric(horizontal: 16.0), // 给容器增加水平方向外边距,指定值为16
          child: Column( // Column(垂直布局)将孩子们按从上到下的顺序放在一起。默认情况下,子项在竖直方向上扩展以填满矩形。
            mainAxisAlignment: MainAxisAlignment.center, // 设置孩子们在主轴方向上(即垂直方向)居中
            children: <Widget>[ // 包括孩子们的列表
              Text( // 带格式的文本内容
                "Title", // 文本内容
                textAlign: TextAlign.center, // 文字居中对齐
                style: TextStyle(fontSize: 28.0, fontWeight: FontWeight.bold), // 设置文本样式
              ),
              SizedBox(height: 16.0), // 添加了一个尺寸框,用于控制组件之间的距离
              ElevatedButton( // Material风格按钮组件,嵌入了类似浮动按钮的设计
                onPressed: () => print("Pressed"), // 按钮被按下时执行的函数调用
                child: Text("Press me"), // 按钮上显示的文字
              ),
              SizedBox(height: 16.0), // 再次添加尺寸框用于控制组件之间的距离
              Row( // 水平布局组件
                mainAxisAlignment: MainAxisAlignment.spaceBetween, // 布置方式:让子部件在水平方向上相等地分开,并且每个部件位于行的两侧。
                children: <Widget>[ // 组件列表
                  ElevatedButton( // 第一个按钮
                    onPressed: () => print("Left pressed"), // 按钮被按下时执行的函数调用
                    child: Text("Left button"), // 按钮上显示的文字
                  ),
                  SizedBox(width: 16.0), // 制作一个固定宽度的空间以控制两个按钮之间的距离。
                  ElevatedButton( // 第二个按钮
                    onPressed: () => print("Right pressed"), // 按钮被按下时执行的函数调用
                    child: Text("Right button"), // 按钮上显示的文字
                  ),
                ],
              )
            ],
          ),
        ),
      ),
    );
  }
}}
}

微信小程序 Button

<view class="container">
  <text class="title">Title</text>
  <button class="primary-button" bindtap="onPressButton">Press me</button>
  <view class="button-group">
    <button class="secondary-button" bindtap="onPressLeftButton">Left button</button>
    <button class="secondary-button" bindtap="onPressRightButton">Right button</button>
  </view>
</view>

/* index.wxss */


.container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  margin: 16px;
}

.title {
  font-size: 28px;
  font-weight: bold;
  text-align: center;
  margin-bottom: 16px;
}

.primary-button {
  width: 100%;
  background-color: #007AFF;
  color: white;
  border-radius: 8px;
  padding: 12px;
  margin-bottom: 16px;
}

.secondary-button {
  background-color: white;
  color: #007AFF;
  border: 1px solid #007AFF;
  border-radius: 8px;
  padding: 12px;
  margin-bottom: 16px;
}

.button-group {
  display: flex;
  justify-content: space-between;
}

// index.js
Page({
  onPressButton: function () {
    console.log('Button pressed')
  },
  onPressLeftButton: function () {
    wx.showToast({
      title: 'Left button pressed',
      icon: 'none'
    })
  },
  onPressRightButton: function () {
    wx.showToast({
      title: 'Right button pressed',
      icon: 'none'
    })
  }
})

React Native Image

import React from 'react';
import { View, Image, StyleSheet } from 'react-native';

// 创建样式表
const styles = StyleSheet.create({
  container: {
    paddingTop: 50,
  },
  tinyLogo: {
    width: 50,
    height: 50,
  },
  logo: {
    width: 66,
    height: 58,
  },
});

// 创建组件
const DisplayAnImage = () => {
  return (
    // 渲染视图容器
    <View style={styles.container}>
      {/* 显示静态图片 */}
      <Image
        style={styles.tinyLogo}
        source={require('@expo/snack-static/react-native-logo.png')}
      />
      {/* 使用 URL 显示远程图片 */}
      <Image
        style={styles.tinyLogo}
        source={{
          uri: 'https://reactnative.dev/img/tiny_logo.png',
        }}
      />
      {/* 使用 Base64 编码的图片数据显示图片 */}
      <Image
        style={styles.logo}
        source={{
          uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==',
        }}
      />
    </View>
  );
}

// 导出组件
export default DisplayAnImage;

Flutter Image

import 'package:flutter/material.dart';

class DisplayAnImage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            // 显示静态图片
            Image.asset(
              'images/flutter-logo.png',
              width: 50,
              height: 50,
            ),
            // 使用 URL 显示远程图片
            Image.network(
              'https://flutter.dev/assets/ui/layout/container-appearance.animation.00.gif',
              width: 50,
              height: 50,
            ),
            // 使用 Base64 编码的图片数据显示图片
            Image.memory(
              _decodeBase64Image(),
              width: 66,
              height: 58,
            ),
          ],
        ),
      ),
    );
  }

  // 解码 Base64 编码的图片数据并返回字节数组
  List<int> _decodeBase64Image() {
    final String base64 =
        'iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==';
    return base64Decode(base64);
  }
}

微信小程序 Image

以下是使用微信小程序实现显示图片的代码:

<!-- display-an-image.wxml -->
<view class="container">
  <!-- 显示静态图片,需要在项目根目录下创建 images 文件夹,并将 react-native-logo.png 图片文件放置于其中 -->
  <image class="tinyLogo" src="/images/react-native-logo.png" />
  <!-- 使用 URL 显示远程图片 -->
  <image class="tinyLogo" src="https://reactnative.dev/img/tiny_logo.png" />
  <!-- 使用 Base64 编码的图片数据显示图片 -->
  <image class="logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==" />
</view>


/* display-an-image.wxss */
.container {
  padding-top: 50rpx;
}
.tinyLogo {
  width: 50rpx;
  height: 50rpx;
}
.logo {
  width: 66rpx;
  height: 58rpx;
}

React Native输入框

import React from 'react';
import { View, TextInput } from 'react-native';

function UselessTextInput(props) {
  return (
    <TextInput
      {...props} // 将父组件传递来的所有props传递给TextInput;比如下面的multiline和numberOfLines
      editable
      maxLength={40}
    />
  );
}

export default function UselessTextInputMultiline() {
  const [value, onChangeText] = React.useState('Useless Multiline Placeholder');

  // 你可以试着输入一种颜色,比如red,那么这个red就会作用到View的背景色样式上
  return (
    <View
      style={{
        backgroundColor: value,
        borderBottomColor: '#000000',
        borderBottomWidth: 1,
      }}>
      <UselessTextInput
        multiline
        numberOfLines={4}
        onChangeText={text => onChangeText(text)}
        value={value}
      />
    </View>
  );
}

Flutter 输入框

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _controller = TextEditingController();

  void _printInputText() {
    print('The input text is: ${_controller.text}');
  }

  
  void dispose() {
    // 需要手动释放 TextEditingController 实例
    _controller.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Flutter TextField Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextField(
              controller: _controller,
              decoration: InputDecoration(
                hintText: 'Please enter some text',
              ),
            ),
            SizedBox(height: 16),
            ElevatedButton(
              onPressed: _printInputText,
              child: Text('Get Input Text'),
            ),
          ],
        ),
      ),
    );
  }
}
上述代码中,我们首先创建了一个名为 MyHomePage 的有状态组件。在该组件内部,我们创建了一个 TextEditingController 实例 _controller 来控制输入框的内容,并在组件销毁时手动释放资源(调用 dispose() 方法)。

然后,在组件的 UI 部分,我们使用了 TextField 组件并将 _controller 传入该组件的 controller 属性中。同时,我们也为输入框添加了一些提示文本,以便用户了解该输入框的用途。

最后,在输入框下方还创建了一个 ElevatedButton 组件,通过点击该按钮来获取输入框中的文本内容。我们这里通过将 _controller.text 的值打印到控制台来演示。

如果您运行上述代码,就会得到一个包含一个输入框和一个按钮的居中显示布局。

在输入框内输入任意文本后,点击按钮可以看到该文本被打印到了控制台上。

微信小程序 输入框

<view class="container" style="background-color: {{value}}; border-bottom-color: #000; border-bottom-width: 1px;">
  <textarea class="input-box" placeholder="Useless Multiline Placeholder" maxlength="40" bindinput="onInput" value="{{value}}" auto-height></textarea>
</view>
.container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 300rpx;
}

.input-box {
  width: 80%;
  height: 150rpx;
  font-size: 32rpx;
  padding: 20rpx;
  border: none;
}

Page({
  data: {
    value: '#ffffff',
  },
  onInput(event) {
    const { value } = event.detail;
    this.setData({
      value,
    });
  },
});

React Native 表单

React Native 中没有内置的表单组件。不过,您可以使用一些库来创建和管理 React Native 表单,例如 formik 和 react-hook-form 等。这些库可以帮助您更方便地进行表单数据处理、校验、提交等操作,并提供了许多有用的工具函数和 API。

下面以 formik 为例,给出一个简单的示例代码:



import React from 'react';
import { View, TextInput, Button } from 'react-native';
import { useFormik } from 'formik';

export default function FormExample() {
  const formik = useFormik({
    initialValues: { name: '', email: '', password: '' },
    validate: (values) => {
      const errors = {};
      if (!values.name) {
        errors.name = 'Required';
      }
      if (!values.email) {
        errors.email = 'Required';
      } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) {
        errors.email = 'Invalid email address';
      }
      if (!values.password) {
        errors.password = 'Required';
      }
      return errors;
    },
    onSubmit: (values) => console.log(values),
  });

  return (
    <View>
      <TextInput
        placeholder="Your Name"
        style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
        onChangeText={formik.handleChange('name')}
        onBlur={formik.handleBlur('name')}
        value={formik.values.name}
      />
      {formik.touched.name && formik.errors.name ? (
        <Text style={{ color: 'red' }}>{formik.errors.name}</Text>
      ) : null}
      <TextInput
        placeholder="Email Address"
        style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
        onChangeText={formik.handleChange('email')}
        onBlur={formik.handleBlur('email')}
        value={formik.values.email}
      />
      {formik.touched.email && formik.errors.email ? (
        <Text style={{ color: 'red' }}>{formik.errors.email}</Text>
      ) : null}
      <TextInput
        secureTextEntry
        placeholder="Password"
        style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
        onChangeText={formik.handleChange('password')}
        onBlur={formik.handleBlur('password')}
        value={formik.values.password}
      />
      {formik.touched.password && formik.errors.password ? (
        <Text style={{ color: 'red' }}>{formik.errors.password}</Text>
      ) : null}
      <Button title="Submit" onPress={formik.handleSubmit} />
    </View>
  );
}

在这个例子中,我们使用 useFormik() hook 创建一个表单实例。initialValues 属性指定了表单的初始值,validate 函数对表单进行校验,onSubmit 函数则定义了当表单提交时应该执行的操作。

我们使用 TextInput 组件创建了三个输入框,并通过 formik.handleChange 方法将其与表单数据绑定起来。每个输入框还监听了 onBlur 事件,在用户输入内容后离开输入框时会立即更新表单状态,从而在下方显示出任何验证错误消息(通过触发 formik.handleBlur 方法实现)。

最后,我们在按钮组件上调用 formik.handleSubmit 方法,触发表单提交操作。

Flutter 表单

import 'package:flutter/material.dart';

// 创建带表单验证的 StatefulWidget 组件
class FormExample extends StatefulWidget {
  
  _FormExampleState createState() => _FormExampleState();
}

// 定义 State 类
class _FormExampleState extends State<FormExample> {
  // 全局变量,用于获取表单对象并进行校验和提交
  final _formKey = GlobalKey<FormState>();

  // 定义三个状态变量,对应表单输入值
  String _name;
  String _email;
  String _password;

  // 表单提交函数,当表单校验通过时触发
  void _submitForm() {
    if (_formKey.currentState.validate()) {
      _formKey.currentState.save(); // 将所有输入框内的数据保存到相应的状态变量中
      print('Name: $_name');
      print('Email: $_email');
      print('Password: $_password');
      // 在这里调用 API 将表单数据提交到服务器处理
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Form Example'),
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Form(
          key: _formKey, // 将 key 属性绑定到我们在构造函数中创建的 GlobalKey 对象
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              // 姓名输入框
              TextFormField(
                decoration: InputDecoration(
                  labelText: 'Your Name',
                  border: OutlineInputBorder(),
                ),
                validator: (value) =>
                    value.isEmpty ? 'Please enter your name.' : null,
                onSaved: (value) => _name = value.trim(),
              ),
              SizedBox(height: 16.0), // 加上一些距离,使视觉效果更佳

              // 邮箱输入框
              TextFormField(
                decoration: InputDecoration(
                  labelText: 'Email Address',
                  border: OutlineInputBorder(),
                ),
                keyboardType: TextInputType.emailAddress,
                textInputAction: TextInputAction.next,
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Please enter your email address.';
                  } else if (!RegExp(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$').hasMatch(value)) {
                    return 'Invalid email address.';
                  }
                  return null;
                },
                onSaved: (value) => _email = value.trim(),
              ),
              SizedBox(height: 16.0),

              // 密码输入框
              TextFormField(
                decoration: InputDecoration(
                  labelText: 'Password',
                  border: OutlineInputBorder(),
                ),
                obscureText: true, // 密码不可见
                validator: (value) =>
                    value.isEmpty ? 'Please enter your password.' : null,
                onSaved: (value) => _password = value.trim(),
              ),
              SizedBox(height: 16.0),

              // 提交按钮
              ElevatedButton(
                child: Text('Submit'),
                onPressed: _submitForm,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

微信小程序表单

使用微信小程序的form组件来创建表单,并使用相关的校验方法进行验证。以下是一个简单的例子:

在wxml文件中定义表单代码如下:

<form bindsubmit="handleSubmit">
  <input name="name" placeholder="请输入姓名"/>
  <input name="age" type="number" placeholder="请输入年龄"/>
  <input name="phone" maxlength="11" placeholder="请输入手机号"/>
  <button formType="submit">提交</button>
</form>

在js文件中,声明 handleSubmit 方法来处理表单提交事件,并在该方法内进行表单数据的校验。代码如下:

Page({
  data: {},
  handleSubmit: function(e) {
    const { detail: { value } } = e;
    
    // 对表单字段进行校验
    if (!value.name || !value.age || !value.phone) {
      wx.showToast({
        title: '请填写完整的信息',
        icon: 'none'
      });
      return;
    }
    if (!/^[1][3,4,5,7,8,9][0-9]{9}$/.test(value.phone)) {
      wx.showToast({
        title: '手机号格式不正确',
        icon: 'none'
      });
      return;
    }

    // 校验通过,执行后续操作
    console.log('提交数据:', value);
  }
})

以上代码的含义是:首先在 handleSubmit 方法中获取表单数据,并按照所需格式进行校验。如果校验不通过,则通过 wx.showToast 方法提示用户出错信息;否则,可以拿到表单数据并进行后续操作,例如将数据发送至服务器等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值