VUE页面结构深度剖析
VUE页面结构
一个vue页面主要包括3个部分:
1.<template>界面展示代码</template>
//其中模板只能包含一个父节点,<router-view/>为<router-view></router-view>的简写,是子路由视图,后面的路由页面都显示在此处。
2.<script>业务实现代码</script>
//vue通常用es6来写,用export default导出,其下面可以包含数据data,生命周期(mounted等),方法(methods)等。
3.<style>界面布局代码</style>
//样式通过style标签<style></style>包裹,默认是影响全局的,如需定义作用域只在该组件下起作用,需在标签上加scoped,<style scoped></style>
重点部分是业务实现
<script>
import {
getCompanyList, //根据条件查询企业
delCompanyInfo, //根据id删除企业
uploadExcel //上传excel文件并导入数据库
} from '@/api/data.js'
import config from '@/config/index.js'
import four from '@/config/four.json' //四级行业分类json数据
export default {
name: "Home",//页面名称
data() { //数据定义
const validateUserName = (rule,value,callback) =>{
//此处用于表单提交时,自定义用户名的校验规则
if (value === '') { //用户名是否为空
callback(new Error('用户名不可以为空'));
} else {
if(value.length<6||value.length>20){ //用户名长度是否处于6-20位
callback(new Error('用户名长度必须介于6至20位'));
}else{
if(value.length==value.replace(/\s+/g,'').length){ //用户名中是否含有空字符串
var reg = /[\u4E00-\u9FA5\uF900-\uFA2D]/ ;
if(reg.test(value)){ //用户名是否含有中文字符
callback(new Error('用户名不能含有中文字符'));
}
callback();
}else{
callback(new Error('用户名不能含有空格字符'));
}
}
}
};
return { //自定义数据
pageNum:0,
colTotal:1,
queryParam{
"pageNum":1,
"companyName":"企业名称"
},
columns2: [{
title: '名称',
key: 'companyName',
align:'center',
},
{
title: '地址',
key: 'street',
align:'center',
},
{
title: '分类',
key: 'industryBelong',
align:'center',
}
{
title: '操作',
key: 'action',
align: 'center',
render: (h, params) => {
return h('div', [
h('Button', {
props: {
type: 'text',
size: 'small'
},
on: {
click: () => {
this.see(params.row.id)
}
}
}, '查看'),
h('Button', {
props: {
type: 'text',
size: 'small'
},
on: {
click: () => {
this.del(params.index,params.row.id)
}
}
}, '删除')
]);
}
}
]
};
},
methods: {
// 组件的方法
changepage(index) {
this.search.pageNo = index
this.list()
},
changepagesize(pageSize) {
this.search.pageSize = pageSize
this.list()
},
edit(id) {
this.$router.push({ //跳转页面
name: 'user_edit',
query: { //跳转页面时的参数
id
}
})
},
list() {
userList(this.search).then(data => {
//此处执行ajax请求userList为自定义ajax请求函数名需要引入该函数
this.tableData = data.res.content
this.total = data.res.totalElements
})
},
},
activated:{
//实例被激活时调用,用于重复激活一个实例的时候
},
deactivated:{
//实例被撤销时调用
},
watch: {
// watch监听方法,擅长处理的场景:一个数据影响多个数据
},
computed: {
// computed擅长处理的场景:一个数据受多个数据影响
},
beforeCreate: function() {
// 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。
},
created: function() {
// 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
},
beforeMount: function() {
// 在挂载开始之前被调用:相关的 render 函数首次被调用。
},
mounted: function() {
// 编译好的HTML挂载到页面完成后执行的事件钩子
// el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。
// 此钩子函数中一般会做一些ajax请求获取数据进行数据初始化例如:
load() { //加载所有企业信息&行业分类信息
//console.log(this.queryParams) //执行ajax查询时的参数
//const msg = this.$Message.loading('正在加载中...', 0);
getCompanyList(this.queryParams).then(data => {//this.currentPage→当前所在页面
if(data.code == 200){ //后台返回状态码
this.data = data.res.list; //数据绑定查询结果→数据绑定
if(this.status){ //状态为真提示查询成功
this.$Message.success("查询成功");
}
}else if(data.code == 500){
this.$Message.error("加载信息失败");
}
else{
this.$Message.error(data.msg);
}
})
}
},
beforeUpdate: function() {
// 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。 你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
},
updated: function() {
// 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
// 当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。
// 该钩子在服务器端渲染期间不被调用。
},
beforeDestroy: function() {
// 实例销毁之前调用。在这一步,实例仍然完全可用。
},
destroyed: function() {
// Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。
}
};
</script>
VUE界面展示代码
{{formCustom.userName}} 普通管理员 超级管理员<template>
<Form ref="formCustom" :model="formCustom" :rules="ruleCustom" :label-width="80">
<FormItem label="用户名:" prop="userName">
{{formCustom.userName}}
<!-- <Input type="text" v-model="formCustom.userName" placeholder="请输入用户名长度介于6至20位"></Input> -->
</FormItem>
<FormItem label="密码:" prop="passwd">
<Input type="password" v-model="formCustom.passwd" placeholder="请输入新密码长度介于6至20位"></Input>
</FormItem>
<FormItem label="确认密码:" prop="passwdCheck">
<Input type="password" v-model="formCustom.passwdCheck" placeholder="请再次输入密码"></Input>
</FormItem>
<FormItem label="权限:" prop="auth">
<RadioGroup v-model="formCustom.auth">
<Radio label="0">普通管理员</Radio>
<Radio label="1">超级管理员</Radio>
</RadioGroup>
</FormItem>
<FormItem>
<Button type="primary" @click="handleSubmit('formCustom')">提交</Button>
<Button @click="handleReset('formCustom')" style="margin-left: 8px">重置</Button>
<Button @click="close()" style="margin-left: 8px">返回</Button>
</FormItem>
</Form>
</template>
<script>
import {
getUser, //通过id查询用户
saveUser //保存用户
} from '@/api/data.js'
import {
mapMutations
} from 'vuex' //用于关闭tabBar
export default {
data() {
const validateUserName = (rule, value, callback) => { //用户名校验规则
if (value === '') { //用户名是否为空
callback(new Error('用户名不可以为空'));
} else {
if (value.length < 6 || value.length > 20) { //用户名长度是否处于6-20位
callback(new Error('用户名长度必须介于6至20位'));
} else {
if (value.length == value.replace(/\s+/g, '').length) { //用户名中是否含有空字符串
var reg = /[\u4E00-\u9FA5\uF900-\uFA2D]/;
if (reg.test(value)) { //用户名是否含有中文字符
callback(new Error('用户名不能含有中文字符'));
}
callback();
} else {
callback(new Error('用户名不能含有空格字符'));
}
}
}
};
const validatePass = (rule, value, callback) => { //密码校验规则
if (value === '') {
callback(new Error('密码不可以为空'));
} else {
if (value.length < 6 || value.length > 20) {
callback(new Error('密码长度必须介于6至20位'));
} else {
var reg = /[\u4E00-\u9FA5\uF900-\uFA2D]/;
if (reg.test(value)) { //密码是否含有中文字符
callback(new Error('密码不能含有中文字符'));
}
if (this.formCustom.passwdCheck !== '') { //对第二个密码框单独验证
this.$refs.formCustom.validateField('passwdCheck');
}
callback();
}
}
};
const validatePassCheck = (rule, value, callback) => { //确认密码校验
if (value === '') {
callback(new Error('确认密码不可以为空'));
} else if (value !== this.formCustom.passwd) {
callback(new Error('两次密码不一致,请重新输入'));
} else {
var reg = /[\u4E00-\u9FA5\uF900-\uFA2D]/;
if (reg.test(value)) { //确认密码是否含有中文字符
callback(new Error('确认密码不能含有中文字符'));
}
callback();
}
};
return {
formCustom: {
userName: '', //用户名
passwd: '', //用户密码
passwdCheck: '', //确认密码
auth: 1 //用户权限
},
ruleCustom: {
userName: [{
required: true,
validator: validateUserName,
trigger: 'blur'
}],
passwd: [{
required: true,
validator: validatePass,
trigger: 'blur'
}],
passwdCheck: [{
required: true,
validator: validatePassCheck,
trigger: 'blur'
}],
auth: [{
required: true,
message: '权限不可以为空,请选择!',
trigger: 'change'
}]
}
}
},
mounted() {
this.load() //自动加载用户信息
},
methods: {
...mapMutations([ //关闭标签栏页面标签
'closeTag'
]),
load() {
this.handleSpinCustom() //打开自动加载悬浮标志
getUser({
id: this.$route.query.id
}).then(data => {
if (data.code == 200) { //能否正常查询用户信息
//console.log(data.res)
this.formCustom.userName = data.res.userName; //编辑用户时显示用户名
// this.formCustom.passwd = data.res.passWord;//编辑用户时不显示密码
// this.formCustom.passwdCheck = data.res.passWord;//编辑用户时不显示请确认密码
if (data.res.auth == 1) { //编辑用户时显示权限
this.formCustom.auth = '1';
} else {
this.formCustom.auth = '0';
}
} else if (data.code == 500) {
this.$Message.error("打开编辑用户失败");
} else {
this.$Message.error(data.msg);
}
this.$Spin.hide(); //关闭自动悬浮加载标志
})
},
handleSubmit(name) { //保存编辑用户
this.$refs[name].validate((valid) => {
if (valid) {
this.$Modal.confirm({
title: '提示',
content: '<p>确定要保存该用户吗?</p>',
onOk: () => {
let param = {
id: this.$route.query.id,
userName: this.formCustom.userName,
passWord: this.formCustom.passwd,
auth: this.formCustom.auth
};
//console.log(param)
this.handleSpinCustom() //打开自动加载悬浮标志
saveUser(param).then(data => {
if (data.code == 200) {
this.$Message.success("用户保存成功");
this.close()
} else if (data.code == 500) {
this.$Message.error("用户保存失败");
} else {
this.$Message.error(data.msg);
}
this.$Spin.hide(); //关闭自动悬浮加载标志
})
},
onCancel: () => {}
});
} else {
this.$Message.error('用户信息不正确,请检查后再提交');
}
})
},
handleReset(name) { //重置用户信息
this.$refs[name].resetFields();
},
close() { //关闭页面标签栏&返回列表页面
/**
* 如果是调用closeTag方法,普通的页面传入的对象参数只需要写name字段即可
* 如果是动态路由和带参路由,需要传入query或params字段,用来区别关闭的是参数为多少的页面
*/
this.closeTag({
name: 'user_edit_page',
query: {
id: this.$route.query.id
}
});
this.$router.push({
name: 'user_page'
});
},
handleSpinCustom () { //自动加载悬浮标志
this.$Spin.show({
render: (h) => {
return h('Form', [
h('Icon', {
'class': 'demo-spin-icon-load',
props: {
type: 'ios-loading',
size: 45
}
}),
h('Form', '加载中')
])
}
});
}
}
}
</script>
VUE项目结构
重点在src文件夹:
assets
静态资源,如css,js ,images,video
components
公共组件
router
路由文件,router下的index.js文件中的routes定义了路径为’/'的路由,该路由对应的页面是HelloWorld组件
App.vue
根组件
main.js
main.js主要是引入vue框架,根组件及路由设置,并且定义vue实例。
components: { App }引入根组件App.vue,App即App:App;
template: ‘’ 是简写形式,等价于 。
整个页面渲染过程:
访问http://localhost:8080/显示的就是index.html页面,index.html原本只有一个根结点id=“app”。
index.html
main.js入口文件引入根组件App。
main.js
前边已说过,根组件App中,是子路由视图,后面的路由页面都显示在此处,访问http://localhost:8080/,路由为‘/’,根据路由文件index.js,所以引入HelloWorld组件。
main.js中的template: ''在html页面中添加模板,模板内容即为HelloWorld组件内容。
App.vue
router
HelloWorld.vue
最后渲染出的html结构如下:
外链图片转存中…(img-sfherbod-1598079565132)]
index.html
main.js入口文件引入根组件App。
[外链图片转存中…(img-oMJT4i2I-1598079565134)]
main.js
前边已说过,根组件App中,是子路由视图,后面的路由页面都显示在此处,访问http://localhost:8080/,路由为‘/’,根据路由文件index.js,所以引入HelloWorld组件。
main.js中的template: ''在html页面中添加模板,模板内容即为HelloWorld组件内容。
[外链图片转存中…(img-1qZ84bBK-1598079565136)]
App.vue
[外链图片转存中…(img-OppNKDQn-1598079565138)]
router
[外链图片转存中…(img-274w34jZ-1598079565140)]
HelloWorld.vue
最后渲染出的html结构如下:
[外链图片转存中…(img-gBxfBY2P-1598079565140)]