这几天在学习vue,就想给我的毕设改善一下,使用vue改写邀请管理员界面,涉及到很多复杂的DOM操作,jquery很难执行,如图:
结果展示图
我从vue-multiselect用到了vue-select,从vue-tagsinput用到vue-input-tag到vue-tagger再到vue-tagsinput,从Browserify用到了Webpack,把vue组件文档看了好几遍,终于做出来了!历时3天!
各种坑
可以跳过,直接看下面的正确解题方法
最开始使用Vue-multiselect,npm安装后,只有一个lib目录,这也是我怀疑此包不能使用的原因,根据官方文档,需要使用:
import Multiselect from 'vue-multiselect'
但是查了一下,chrome不支持此语法,所以借助babel转换为es5:Babel在线转换es6
然而,将下面的js(官方文档)转换后:
<script>
import Multiselect from 'vue-multiselect'
// register globally
Vue.component(Multiselect)
export default {
// OR register locally
components: { Multiselect },
data () {
return {
value: null,
options: ['list', 'of', 'options']
}
}
}
</script>
并不能在浏览器中使用,因为其中含有require()语句,这是node语法,需要commonJs环境,然后找到Browserify ,可以转换js在浏览器中使用,但是转换过程中报错
Error: Cannot find module 'vueify' from '/home/lyndon/work/FormReview/public/node_modules/vue-multiselect'
没有安装vueify,查了一下:
If I then install vueify with --legacy-bundling it works fine.
$ npm install --legacy-bundling vueify
- balanced-match...
$ ./node_modules/.bin/browserify -t vueify -o app.js main.js; echo $?
0
又报错:
Error: Cannot find module 'babelify' from '/home/lyndon/work/FormReview/public/node_modules/vue-multiselect'
接着又安装了:
"devDependencies": {
"babel-cli": "~6.24.1",
"babel-core": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"babel-runtime": "^6.23.0",
"babelify": "^7.3.0",
"browserify": "^14.3.0",
"vueify": "^9.4.1"
},
./node_modules/.bin/browserify -t vueify -e assets/js/invite.js -o assets/js/build/invite.js
这些乱七八糟的库,这下终于转换成功了,但是,使用此js,浏览器还是报错了。
然后,按照vueify上面所说,写了
demo.vue:
<template>
<div>
<multiselect v-model="value" :options="options"></multiselect>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
export default {
components: {
Multiselect
},
data () {
return {
value: '',
options: ['Select option', 'options', 'selected', 'mulitple', 'label', 'searchable', 'clearOnSelect', 'hideSelected', 'maxHeight', 'allowEmpty', 'showLabels', 'onChange', 'touched']
}
}
}
</script>
invite.js:
var Vue = require('vue');
var App = require('./demo.vue');
var vm = new Vue({
el: '#vm-form',
render: function (createElement) {
return createElement(App)
},
...
继续转换编译,成功,然后刷新浏览器,这下好了,浏览器报了一大堆错误
永不言弃
学习vue组件和webpack:
在webpack-simple示例项目中修改,加入vue-multiselect,编译后各种错误,改成Vue-select,成功运行!哈哈哈!
使用npm run build
编译出js文件!
在组件中使用vue-resource一直报错,最后使用axios:
// invite.vue:
import axios from 'axios';
axios.get('/web/admin/getOwnForms')...
'change-input': {
created: function () {
window.inp = this;
},
props: ['condition'],
render: function (createElement) {
var self = this
console.log(this.condition);
if (this.condition.field != null && ['checkbox-group', 'radio-group', 'select'].indexOf(this.condition.field.type) != -1) {
return createElement(
'v-select',
{
multiple,
attrs: {
'v-model': "condition.value",
':options': "condition.field.values"
},
domProps: {
value: self.condition.value
},
on: {
input: function (event) {
self.condition.value = event.target.value
}
}
}
);
} else {
//'<input-tag placeholder="回车输入下一个关键词" :tags="condition.value" validate="text"></input-tag>'
return createElement(
'input',
{
attrs: {
type: "text",
placeholder:"“,”分割关键词"
},
domProps: {
value: self.condition.value
},
on: {
input: function (event) {
self.condition.value = event.target.value
}
}
}
);
}
}
}
根据表单控件动态变换后面的填写域,但是实际不会跟着改变。故采用动态组件。
但是又有问了,一开始conditions为计算属性,根据add_condition改变而改变,watch这个conditions只有第一次有用,改成深度监听也不行,改变策略,将conditions改为正常属性,watch add_condition和conditions,这下点加号conditions增加一个object,页面也跟着变化了。
正确解题方法
- 安装webpack环境:
- 可以根据webpack-simple安装方法,使用vue-cli安装。
- 也可以直接运行npm init生成package.json文件,改写该文件,加入webpack,然后运行npm install,如果根目录没有.babelrc文件,必须加上:
.babelrc:
{
"presets": [
["latest", {
"es2015": { "modules": false }
}]
]
}
webpack.config.js:
module.exports = {
//输入路径
entry: './assets/js/src/invite.js',
//输出路径
output: {
path: path.resolve(__dirname, './assets/js'),
publicPath: '/assets/js/',
filename: 'invite.js'
},
...
主要文件:
invite.js:
import Vue from 'vue'
import App from './invite.vue'
new Vue({
el: '#app',
render: h => h(App)
});
invite.vue:
<template>
<div id="app">
<form id="form" @submit.prevent="submit" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-2 control-label">表单</label>
<div class="col-sm-10">
<v-select label="name" v-model="form" :options="forms"></v-select>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">权限</label>
<div class="col-sm-10">
<v-select multiple v-model="authority" :options="authorities"></v-select>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">审核阶段</label>
<div class="col-sm-10">
<v-select multiple v-model="stage" :options="stages"></v-select>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">筛选</label>
<div class="col-sm-10">
<div class="bootstrap-switch-square">
<input type="checkbox" v-model="add_condition" id="condition"/>
</div>
</div>
</div>
<template v-if="add_condition">
<div class="form-group conditions" v-for="(condition,index) in conditions">
<label class="col-sm-2 control-label">条件{{index+1}}</label>
<div class="col-sm-4">
<v-select v-model="condition.field" :options="fields"></v-select>
</div>
<div class="col-sm-5">
<component :is="condition.input" :condition="condition"></component>
</div>
<div class="col-sm-1">
<span v-if="index>0" class="glyphicon glyphicon-minus" aria-hidden="true" @click="addCondition(-1,index)"></span>
<span class="glyphicon glyphicon-plus" aria-hidden="true" @click="addCondition(1,index)"></span>
</div>
</div>
</template>
<div class="form-group">
<label class="col-sm-2 control-label">用户</label>
<div class="col-sm-10">
<v-select multiple
v-model="user"
:debounce="250"
:on-search="getUsers"
:options="users"
placeholder="搜索用户"
>
</v-select>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">备注</label>
<div class="col-sm-10">
<textarea v-model="remark" class="form-control" rows="3"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">发送邀请</button>
</div>
</div>
</form>
</div>
</template>
<script>
import vSelect from "vue-select"
import axios from 'axios'
import tagsInput from 'vue-tagsinput'
export default {
components: {
vSelect,
tagsInput,
'select-input': {
components: {
vSelect
},
props: ['condition'],
template: '<v-select multiple v-model="condition.value" :options="condition.field.values"></v-select>'
},
'text-input': {
components: {
tagsInput
},
props: ['condition'],
template: '<tags-input placeholder="Tab键确认关键词" @tags-change="handleChange" :tags="condition.value"></tags-input>',
methods: {
handleChange: function handleChange(index, text) {
if (text) {
this.condition.value.splice(index, 0, text);
} else {
this.condition.value.splice(index, 1);
}
}
}
}
},
data() {
return {
forms: [],
form: null,
authorities: [],
authority: [],
stage: [],
add_condition: false,
conditions: [],
users: [],
user: [],
remark: ''
}
},
created: function () {
this.init();
},
methods: {
init: function () {
axios.get('/web/admin/getOwnForms').then(response => {
let fid = getQueryString('formId');
fid = fid != null ? parseInt(fid) : null;
this.forms = response.data;
this.forms.forEach(form => {
if (fid != null && fid == form.id) {
this.form = form;
}
form.value = form.id;
form.label = form.name;
});
}).catch(function (error) {
console.log(error);
});
axios.get('/web/admin/getAuthorities').then(response => {
let auths = response.data;
for (let auth in auths) {
let a = {};
a.value = auth;
a.label = auths[auth];
this.authorities.push(a);
}
}).catch(function (error) {
console.log(error);
});
},
addCondition: function (way,index) {
if(way>0) {
this.conditions.push({
field: null,
value: [],
input: 'text-input'
});
}else {
this.conditions.splice(index,1)
}
},
getUsers: function (search, loading) {
loading(true);
axios.get('/web/admin/getExceptUsers', {
params: {
q: search
}
}).then(resp => {
this.users = [];
let users = resp.data;
users.forEach((user, i) => {
let a = {};
a.value = user.id;
a.label = user.name + '|' + user.phone + '|' + user.email;
this.users.push(a);
});
loading(false)
})
},
submit: function () {
let conditions = [];
this.conditions.forEach(c => {
let v = [];
c.value.forEach(val => {
if (typeof val == 'object' && typeof val.value != 'undefined') {
v.push(val.value);
} else {
v.push(val)
}
});
conditions.push({
label: c.field.label,
key: c.field.name,
value: v.join(',')
});
});
let authorities = [];
this.authority.forEach(a => {
authorities.push(a.value);
});
let stages = [];
this.stage.forEach(s => {
stages.push(s.value);
});
let users = [];
this.user.forEach(u => {
users.push(u.value);
});
axios.post('/web/admin', {
tableId: this.form.id,
add_condition: this.add_condition,
conditions: conditions,
authorities: authorities,
stages: stages,
users: users,
remark: this.remark
}).then(function (response) {
if (response.status == 200) {
toastr.success('成功发送邀请');
}
}).catch(function (error) {
console.log(error);
});
}
},
computed: {
stages: function () {
let s = [];
if (this.form) {
let reviewTimes = this.form.reviewTimes;
for (let i = 0; i < reviewTimes; i++) {
s.push({
value: i,
label: reviewTime2zh(i)
});
}
}
return s;
},
fields: function () {
if (this.form) {
return JSON.parse(this.form.fields);
}
return [];
}
},
watch: {
add_condition: function (val) {
if (val) {
this.conditions = [{
field: null,
value: [],
input: 'text-input'
}];
}
},
conditions: {
handler: function (val) {
val.forEach((item, i) => {
if (typeof item != 'undefined' && item.field != null && ['checkbox-group', 'radio-group', 'select'].indexOf(item.field.type) != -1) {
item.input = 'select-input';
} else {
item.input = 'text-input';
}
});
},
deep: true
}
}
};
</script>
invite.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">邀请管理员</div>
<div class="panel-body">
<div id="app"></div>
</div>
</div>
</div>
</div>
</div>
@endsection
@section('js')
<script src="{{cdnAsset('/assets/js/invite.js')}}"></script>
@endsection
网友评论