u-form-item.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <template>
  2. <view class="u-form-item">
  3. <view
  4. class="u-form-item__body"
  5. @tap="clickHandler"
  6. :style="[$u.addStyle(customStyle), {
  7. flexDirection: parentData.labelPosition === 'left' ? 'row' : 'column'
  8. }]"
  9. >
  10. <!-- 微信小程序中,将一个参数设置空字符串,结果会变成字符串"true" -->
  11. <slot name="label">
  12. <view
  13. class="u-form-item__body__left"
  14. v-if="required || leftIcon || label"
  15. :style="{
  16. width: $u.addUnit(labelWidth || parentData.labelWidth),
  17. marginBottom: parentData.labelPosition === 'left' ? 0 : '5px',
  18. }"
  19. >
  20. <!-- 为了块对齐 -->
  21. <view class="u-form-item__body__left__content">
  22. <!-- nvue不支持伪元素before -->
  23. <text
  24. v-if="required"
  25. class="u-form-item__body__left__content__required"
  26. >*</text>
  27. <view
  28. class="u-form-item__body__left__content__icon"
  29. v-if="leftIcon"
  30. >
  31. <u-icon
  32. :name="leftIcon"
  33. :custom-style="leftIconStyle"
  34. ></u-icon>
  35. </view>
  36. <text
  37. class="u-form-item__body__left__content__label"
  38. :style="[parentData.labelStyle, {
  39. justifyContent: parentData.labelAlign === 'left' ? 'flex-start' : parentData.labelAlign === 'center' ? 'center' : 'flex-end'
  40. }]"
  41. >{{ label }}</text>
  42. </view>
  43. </view>
  44. </slot>
  45. <view class="u-form-item__body__right">
  46. <view class="u-form-item__body__right__content">
  47. <view class="u-form-item__body__right__content__slot">
  48. <slot />
  49. </view>
  50. <view
  51. class="item__body__right__content__icon"
  52. v-if="$slots.right"
  53. >
  54. <slot name="right" />
  55. </view>
  56. </view>
  57. </view>
  58. </view>
  59. <slot name="error">
  60. <text
  61. v-if="!!message && parentData.errorType === 'message'"
  62. class="u-form-item__body__right__message"
  63. :style="{
  64. marginLeft: $u.addUnit(labelWidth || parentData.labelWidth)
  65. }"
  66. >{{ message }}</text>
  67. </slot>
  68. <u-line
  69. v-if="borderBottom"
  70. :color="message && parentData.errorType === 'border-bottom' ? $u.color.error : $u.props.line.color"
  71. :customStyle="`margin-top: ${message ? '5px' : 0}`"
  72. ></u-line>
  73. </view>
  74. </template>
  75. <script>
  76. import props from './props.js';
  77. /**
  78. * Form 表单
  79. * @description 此组件一般用于表单场景,可以配置Input输入框,Select弹出框,进行表单验证等。
  80. * @tutorial https://www.uviewui.com/components/form.html
  81. * @property {String} label input的label提示语
  82. * @property {String} prop 绑定的值
  83. * @property {String | Boolean} borderBottom 是否显示表单域的下划线边框
  84. * @property {String | Number} labelWidth label的宽度,单位px
  85. * @property {String} rightIcon 右侧图标
  86. * @property {String} leftIcon 左侧图标
  87. * @property {Boolean} required 是否显示左边的必填星号,只作显示用,具体校验必填的逻辑,请在rules中配置 (默认 false )
  88. *
  89. * @example <u-form-item label="姓名" prop="userInfo.name" borderBottom ref="item1"></u-form-item>
  90. */
  91. export default {
  92. name: 'u-form-item',
  93. mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
  94. data() {
  95. return {
  96. // 错误提示语
  97. message: '',
  98. parentData: {
  99. // 提示文本的位置
  100. labelPosition: 'left',
  101. // 提示文本对齐方式
  102. labelAlign: 'left',
  103. // 提示文本的样式
  104. labelStyle: {},
  105. // 提示文本的宽度
  106. labelWidth: 45,
  107. // 错误提示方式
  108. errorType: 'message'
  109. }
  110. }
  111. },
  112. // 组件创建完成时,将当前实例保存到u-form中
  113. mounted() {
  114. this.init()
  115. },
  116. methods: {
  117. init() {
  118. // 父组件的实例
  119. this.updateParentData()
  120. if (!this.parent) {
  121. uni.$u.error('u-form-item需要结合u-form组件使用')
  122. }
  123. },
  124. // 获取父组件的参数
  125. updateParentData() {
  126. // 此方法写在mixin中
  127. this.getParentData('u-form');
  128. },
  129. // 移除u-form-item的校验结果
  130. clearValidate() {
  131. this.message = null
  132. },
  133. // 清空当前的组件的校验结果,并重置为初始值
  134. resetField() {
  135. // 找到原始值
  136. const value = uni.$u.getProperty(this.parent.originalModel, this.prop)
  137. // 将u-form的model的prop属性链还原原始值
  138. uni.$u.setProperty(this.parent.model, this.prop, value)
  139. // 移除校验结果
  140. this.message = null
  141. },
  142. // 点击组件
  143. clickHandler() {
  144. this.$emit('click')
  145. }
  146. },
  147. }
  148. </script>
  149. <style lang="scss" scoped>
  150. @import "../../libs/css/components.scss";
  151. .u-form-item {
  152. @include flex(column);
  153. font-size: 14px;
  154. color: $u-main-color;
  155. &__body {
  156. @include flex;
  157. padding: 10px 0;
  158. &__left {
  159. @include flex;
  160. align-items: center;
  161. &__content {
  162. position: relative;
  163. @include flex;
  164. align-items: center;
  165. padding-right: 10rpx;
  166. flex: 1;
  167. &__icon {
  168. margin-right: 8rpx;
  169. }
  170. &__required {
  171. position: absolute;
  172. left: -9px;
  173. color: $u-error;
  174. line-height: 20px;
  175. font-size: 20px;
  176. top: 3px;
  177. }
  178. &__label {
  179. @include flex;
  180. align-items: center;
  181. flex: 1;
  182. color: $u-main-color;
  183. font-size: 15px;
  184. }
  185. }
  186. }
  187. &__right {
  188. flex: 1;
  189. &__content {
  190. @include flex;
  191. align-items: center;
  192. flex: 1;
  193. &__slot {
  194. flex: 1;
  195. /* #ifndef MP */
  196. @include flex;
  197. align-items: center;
  198. /* #endif */
  199. }
  200. &__icon {
  201. margin-left: 10rpx;
  202. color: $u-light-color;
  203. font-size: 30rpx;
  204. }
  205. }
  206. &__message {
  207. font-size: 12px;
  208. line-height: 12px;
  209. color: $u-error;
  210. }
  211. }
  212. }
  213. }
  214. </style>