VueCli提供一個(gè)插件可以進(jìn)行原型快速開發(fā)
-
安裝
npm install -g @vue/cli-service-global
-
使用
vue serve
在開發(fā)環(huán)境模式下零配置為 .js 或 .vue 文件啟動一個(gè)服務(wù)器 Options: -o, --open 打開瀏覽器 -c, --copy 將本地 URL 復(fù)制到剪切板 -h, --help 輸出用法信息
-
創(chuàng)建App.vue文件
<template> <h1>Hello!</h1> </template>
-
運(yùn)行
vue serve
vue serve會在當(dāng)前目錄自動推導(dǎo)入口文件——入口可以是
main.js
粱檀、index.js
芬探、App.vue
或app.vue
中的一個(gè)可以顯式地指定入口文件:
vue serve MyComponent.vue
安裝ElementUI
-
創(chuàng)建文件肩祥,初始化package.json
mkdir custom-component cd custom-component yarn init -y
-
安裝ElementUI
vue add element
-
創(chuàng)建main.js竹宋,加載ElementUI叼耙,使用Vue.use()安裝插件
import Vue from 'vue' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' import Login from './src/Login.vue' Vue.use(ElementUI) new Vue({ el: '#app', render: h => h(Login) })
-
創(chuàng)建src/Login.vue鼻疮,并使用vue serve運(yùn)行
<template> <el-form class="form" ref="form" :model="user" :rules="rules"> <el-form-item label="用戶名" prop="username"> <el-input v-model="user.username"></el-input> </el-form-item> <el-form-item label="密碼" prop="password"> <el-input type="password" v-model="user.password"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="login">登 錄</el-button> </el-form-item> </el-form> </template> <script> export default { name: 'Login', data() { return { user: { username: '', password: '', }, rules: { username: [ { required: true, message: '請輸入用戶名', }, ], password: [ { required: true, message: '請輸入密碼', }, { min: 6, max: 12, message: '請輸入6-12位密碼', }, ], }, } }, methods: { login() { this.$refs.form.validate((valid) => { if (valid) { alert('驗(yàn)證成功') } else { alert('驗(yàn)證失敗') return false } }) }, }, } </script> <style> .form { width: 30%; margin: 150px auto; } </style>
組件開發(fā)
步驟條組件
-
創(chuàng)建Steps.vue
<template> <div class="lg-steps"> <div class="lg-steps-line"></div> <div class="lg-step" v-for="index in count" :key="index" :style="{ color: active >= index ? activeColor : defaultColor }" > {{ index }} </div> </div> </template> <script> import './steps.css' export default { name: 'LgSteps', props: { count: { type: Number, default: 3, }, active: { type: Number, default: 0, }, activeColor: { type: String, default: 'red', }, defaultColor: { type: String, default: 'green', }, }, } </script> <style></style>
使用
vue serve ./Steps.vue
運(yùn)行琳水,打開頁面訪問此組件 -
創(chuàng)建Steps-test.vue組件,進(jìn)行測試
<template> <div> <steps :count="count" :active="active"></steps> <button @click="next">下一步</button> </div> </template> <script> import Steps from './Steps.vue' export default { components: { Steps, }, data() { return { count: 4, active: 0, } }, methods: { next() { if (this.active < this.count) { this.active++ } }, }, } </script> <style></style>
表單組件
模仿Element的Form組件吊档,在src下創(chuàng)建form文件夾
-
創(chuàng)建Form.vue篙议、FormItem.vue、Input.vue以及Button.vue組件
<!-- Form.vue --> <template> <form> <slot></slot> </form> </template> <script> export default { name: 'wangForm', props: { model: { type: Object }, rules: { type: Object } } } </script> <style> </style> <!-- FormItem.vue --> <template> <div> <label>{{ label }}</label> <div> <slot></slot> <p v-if="errMessage">{{ errMessage }}</p> </div> </div> </template> <script> export default { name: 'wangFormItem', props: { label: { type: String }, prop: { type: String } }, data () { return { errMessage: '' } } } </script> <style> </style> <!-- Input.vue --> <template> <div> <input v-bind="$attrs" :type="type" :value="value" @input="handleInput"> </div> </template> <script> export default { name: 'wangInput', // 禁用父組件默認(rèn)屬性 inheritAttrs: false, props: { value: { type: String }, type: { type: String, default: 'text' } }, methods: { handleInput (evt) { this.$emit('input', evt.target.value) } } } </script> <style> </style> <!-- Button.vue --> <template> <div> <button @click="handleClick"><slot></slot></button> </div> </template> <script> export default { name: 'wangButton', methods: { handleClick (evt) { this.$emit('click', evt) evt.preventDefault() } } } </script> <style></style>
-
創(chuàng)建Form-test.vue測試組件
<template> <wang-form class="form" ref="form" :model="user" :rules="rules"> <wang-form-item label="用戶名" prop="username"> <!-- <wang-input v-model="user.username"></wang-input> --> <wang-input :value="user.username" @input="user.username=$event" placeholder="請輸入用戶名"></wang-input> </wang-form-item> <wang-form-item label="密碼" prop="password"> <wang-input type="password" v-model="user.password"></wang-input> </wang-form-item> <wang-form-item> <wang-button type="primary" @click="login">登 錄</wang-button> </wang-form-item> </wang-form> </template> <script> import WangForm from './form/Form' import WangFormItem from './form/FormItem' import WangInput from './form/Input' import WangButton from './form/Button' export default { components: { WangForm, WangFormItem, WangInput, WangButton }, data () { return { user: { username: '', password: '' }, rules: { username: [ { required: true, message: '請輸入用戶名' } ], password: [ { required: true, message: '請輸入密碼' }, { min: 6, max: 12, message: '請輸入6-12位密碼' } ] } } }, methods: { login () { console.log('button') // this.$refs.form.validate(valid => { // if (valid) { // alert('驗(yàn)證成功') // } else { // alert('驗(yàn)證失敗') // return false // } // }) } } } </script> <style> .form { width: 30%; margin: 150px auto; } </style>
vue serve ./src/Form-test.vue
運(yùn)行 -
設(shè)置表單驗(yàn)證
表單驗(yàn)證原則:input組件中觸發(fā)自定義事件validate怠硼、FormItem渲染完畢注冊自定義事件validate
修改Input.vue
... <script> export default { ... methods: { // input組件中觸發(fā)自定義事件validate // FormItem渲染完畢注冊自定義事件validate handleInput (evt) { this.$emit('input', evt.target.value) // 找input的父組件 const findParent = parent => { while (parent) { if (parent.$options.name === 'LgFormItem') { break } else { parent = parent.$parent } } return parent } const parent = findParent(this.$parent) // 如果找到就觸發(fā)自定義事件 if (parent) { parent.$emit('validate') } } } } </script>
需要在Fome.vue中將Form組件實(shí)例注冊依賴
provide () { return { form: this } }
修改FormItem.vue鬼贱,使用async-validator進(jìn)行驗(yàn)證
... <script> import AsyncValidator from 'async-validator' export default { name: 'WangFormItem', inject: ['form'], ... mounted () { this.$on('validate', () => { this.validate() }) }, methods: { validate () { // 如果沒有prop 就不需要驗(yàn)證 if (!this.prop) return const value = this.form.model[this.prop] const rules = this.form.rules[this.prop] const descriptor = { [this.prop]: rules } const validator = new AsyncValidator(descriptor) return validator.validate({ [this.prop]: value }, errors => { if (errors) { this.errMessage = errors[0].message } else { this.errMessage = '' } }) } } } </script> <style> </style>
修改Form.vue,提供validate方法
methods: { validate (cb) { // 過濾出含有prop驗(yàn)證的節(jié)點(diǎn) 執(zhí)行validate方法 返回promise對象 const tasks = this.$children .filter(child => child.prop) .map(child => child.validate()) Promise.all(tasks) .then(() => cb(true)) .catch(() => cb(false)) } }
此時(shí)重新運(yùn)行香璃,開啟表單驗(yàn)證
項(xiàng)目地址