一个vue程序模板
代码结构
1.main.js
import { createApp } from 'vue'
import App from './App.vue'
import Index from './Index.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 导入封装好的axios并挂载到Vue全局属性上
import Axios from 'axios'
const app = createApp(Index)
app.use(ElementPlus)
app.use(router)
app.config.globalProperties.$axios = Axios;
app.mount('#app')
2.Index.vue
<template>
<el-container>
<el-header>
<el-row>
<el-col :span="4" style="border: 5px solid black">
<div class="grid-content bg-purple">logo</div>
</el-col>
<el-col :span="20" style="border: 5px solid black">
<router-link to="/">主页</router-link>
<router-link to="/news">新闻</router-link>
<router-link to="/picture">图片</router-link>
<router-link to="/login">登录</router-link>
</el-col>
</el-row>
</el-header>
<div class="main">
<router-view/>
</div>
</el-container>
</template>
<script>
export default {
name: 'Index',
}
</script>
<style>
* {
box-sizing: border-box;
}
body,html{
height: 100%;
}
.el-header{
margin: 0!important;
padding: 0!important;
}
.el-header .el-row{
height: 100%;
}
.el-header .el-row .el-col{
display: flex;
align-items: center;
}
.el-header .el-row .el-col *{
margin: 20px;
}
.el-header{
margin-bottom: 1rem!important;
}
</style>
3.vue.config.js
module.exports = {
devServer:{
port:8090
}
};
4.index.js
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: () => import(/* webpackChunkName: "about" */ '../views/Home.vue'),
},
{
path: '/news',
name: 'news',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/News.vue'),
//添加meta属性,不可任意起名
meta:{
// loginRequest是一个表示符,可以任意起
loginRequest:true,
}
},
{
path: '/login',
name: 'login',
component: () => import(/* webpackChunkName: "about" */ '../views/Login.vue'),
},
{
path: '/picture',
name: 'picture',
component: () => import(/* webpackChunkName: "about" */ '../views/Picture.vue'),
},
];
const router = createRouter({
history: createWebHashHistory(),
routes
});
//添加路由拦截
/*
router.beforeEach((to, from, next) => { } 三个参数:
to:即将要进入的目标 路由对象
from:当前导航正要离开的路由
next:(function函数) 调用next() 进行管道中的下一个钩子
next() 无参 进行 下一个钩子函数
next({ path:'/xxx' , query:{}}) 携带参数跳到xxx页面
*/
router.beforeEach((to,from,next)=>{
if (to.meta.loginRequest){//如果要去的路由的meta对象的loginRequest属性为true
if (sessionStorage.getItem('user')) {//如果已经登录,进入目标界面
next();
}else {//用户没有登录,直接去登录界面
next({
path: '/login',
query:{
//把目标界面的页面路径作为参数传到登录界面,方便登录后跳转目标界面
redirect:to.fullPath
}
});
}
}else {//其他界面情况
next();
}
});
export default router
5.Side.vue
<template>
<div>
<!-- 通过lable改变isCollapse的值-->
<!-- <el-radio-group v-model="isCollapse" style="margin-bottom: 20px">-->
<!-- <el-radio-button :label="false">expand</el-radio-button>-->
<!-- <el-radio-button :label="true">collapse</el-radio-button>-->
<!-- </el-radio-group>-->
<!--
default-active:默认点击
:collapse 是否折叠
el-menu是主目录
el-menu-item是一个目录下的元素
el-sub-menu是子目录
-->
<el-menu
default-active="2"
:collapse="isCollapse"
@open="handleOpen"
@close="handleClose"
>
<el-menu-item index="0" @click="changeState">
<el-icon><aim /></el-icon>
<!--伸展的时候在里面显示,折叠的时候在外面显示 #title是标题-->
<template #title>{{stateInfo}}</template>
</el-menu-item>
<el-menu-item index="{{index}}" v-for="(data, index) in datas" @click="See(data.url)">
<el-icon><Document /></el-icon>
<template #title>
<div @click="See(data.url)">{{data.description}}</div>
</template>
</el-menu-item>
</el-menu>
</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
import {
Location,
Document,
Menu as IconMenu,
Setting,
Aim
} from '@element-plus/icons'
export default {
name: 'Side',
props: ['contents'],
components: {
Location,
Document,
Setting,
IconMenu,
Aim
},
data(){
return{
stateInfo:"展开",
isCollapse:true,
datas:[],
}
},
setup() {
// ref("小黑"):生成变量,这是一个对象,需借助.value来赋值
// let isCollapse = ref(true);
const handleOpen = (key, keyPath) => {
// console.log(key, keyPath)
};
const handleClose = (key, keyPath) => {
// console.log(key, keyPath)
};
return {
handleOpen,
handleClose,
}
},
methods:{
changeState() {
this.isCollapse=!this.isCollapse;
if(this.isCollapse){
this.stateInfo="展开";
}else {
this.stateInfo="收缩";
}
},
See (e) {
window.location.href = e
}
},
created: function () {
var self = this;
this.$axios.get(this.contents)
.then(function (res) {
console.log(res);
self.datas = res.data;
}).catch(function (error) { // 请求失败处理
console.log(error);
});
console.log(this.contents);
},
}
</script>
6.Picture.vue
<template>
<div style="display: flex">
<Side :contents="src"/>
<PictureRight/>
</div>
</template>
<script>
import Side from './Side'
import PictureRight from './PictureRight'
export default {
name: "Slider",
data(){
return{
src:"http://www.xlcode.top/img/kinds/"
}
},
components: {
Side,
PictureRight
}
}
</script>
<style scoped>
.main{
height: 100%;
background: #ff6436;
}
</style>
7.PictureRight.vue
<template>
aaaaa
</template>
<style scoped>
</style>
8.Login.vue
<template>
<div class="login">
<div class="container">
<el-image
:src="url"
class="img"
></el-image>
<!--
ref 属性涉及Dom 元素的获取(el-form表单对象)。
javaSrcipt 获取Dom 元素是通过:document.querySelector(".input")获取dom元素节点 。
Vue 为简化DOM获取方法提出了ref 属性和$refs 对象。一般的操作流程是ref 绑定控件,$refs 获取控件。
这里用ff来标记这个表单,this.$refs['ff']来获得表单
-->
<el-form
ref="ff"
:model="formItems"
:rules="rules">
<!--label-width:标签的宽度-->
<!--label:标签-->
<!--
Vue组件库element-ui中的Form表单组件提供了表单验证功能
通过rules属性传入验证规则
Form-Item中的prop属性设置需要校验的字段名,要和rules对象中保持一致,
也等价于要和表单的属性名称保持一致
-->
<!--el-form-item元素的prop属性绑定字段名account,表单验证时,
就会验证el-input元素绑定的变量formItems.account的值是否符合验证规则-->
<el-form-item label="账号" prop="account">
<el-input v-model="formItems.account"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<!--show-password:密码框-->
<el-input v-model="formItems.password" show-password></el-input>
</el-form-item>
<!--提交按钮-->
<el-form-item>
<el-button type="primary" @click="submitForm('ff')">Create</el-button>
<el-button @click="resetForm('ff')">Reset</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script lang="">
//导出组件
export default {
data() {
return {
//图片地址
url: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg',
//表单属性对象,和表单进行双向绑定:model
formItems: {
//账号
account: '',
// 密码
password:''
},
//验证规则对象,其中的属性名称要和表单对象的属性名称保持一致,否则会失效
rules: {
account: [
{
required: true,
//错误提示
message: '请输入账号',
//事件,只有两个选项blur / change
trigger: 'blur',
},
{
min: 3,
max: 5,
message: '账号3到5位',
trigger: 'blur',
},
],
password: [
{
required: true,
//输入框类型
message: '请示入密码',
trigger: 'blur',
},
],
},
}
},
methods: {
//提交点击事件,传入表单属性对象
submitForm(formName) {
//this.$refs[formName]获得这个表单,然后执行validate方法进行校验,
// 这里的校验是点击按钮之后才会进行的校验
this.$refs['ff'].validate((valid) => {
if (valid) {
//获得正确的属性
console.log(this.formItems.account+":"+this.formItems.password);
//在缓存中存贮用户信息,sessionStorage的过期时间就是关闭浏览器,是个临时会话窗口,
// localStorage,这个好处就是存储空间大,长时间保存,同一浏览器,标签页全部共享,
// 它是直接存到电脑硬盘上的
// localStorage.setItem("user",this.formItems.account);
sessionStorage.setItem("user",this.formItems.account);
/*
| this.$route:当前激活的路由的信息对象。每个对象都是局部的,
可以获取当前路由的 path, name, params, query 等属性。
| this.$router:全局的 router 实例。通过 vue 根实例中注入 router 实例,
然后再注入到每个子组件,从而让整个应用都有路由功能。其中包含了很多属性和对象
(比如 history 对象),任何页面也都可以调用其 push(), replace(), go() 等方法。
*/
//获得路由携带的参数,没有的话就指定'/'
let redirect = this.$route.query.redirect || '/';
//路由调转
this.$router.push({path:redirect})
} else {
console.log('error submit!!');
return false
}
})
},
//重置点击事件
resetForm(formName) {
this.$refs[formName].resetFields()
},
},
}
</script>
<style>
div.login{
width: 100%;
height: 100%;
position: fixed;
left:0;
top: 0;
background: #ff792f;
}
.container{
position: absolute;
left: 50%;
top: 50%;
/*向左和上偏移半个身位*/
transform: translate(-50%, -50%);
background: #70e53f;
padding: 30px!important;
/*width: 400px;*/
/*height: 300px;*/
}
div.login div.container .img{
width: 100px;
height: 100px;
margin-bottom: 20px;
border-radius:50%;
}
</style>
9.News.vue
<template>
<el-row >
<el-col :span="4" style="border: 5px solid black">
<el-aside width="200px" class="hidden-sm-only">
<!--监听子组件的up函数,用receive(自定义方法)来接受函数-->
<Side :contents="src" v-on:up='receive' v-on:up2='receive2' style="position: fixed"/>
</el-aside>
</el-col>
<el-col :span="20" style="border: 5px solid #3dfff7">
<el-container style="border: 1px solid red">
<el-main>
<NewsRight ref="www"/>
</el-main>
<el-footer>Footer</el-footer>
</el-container>
</el-col>
</el-row>
</template>
<script>
import Side from './NewsLeft'
import NewsRight from './NewsRight'
export default {
name: "About",
data(){
return{
src:"http://www.xlcode.top:8082/searchType",
content:"",
}
},
methods:{
// 父组件中响应子组件自定义的方法
// 此函方法的参数是用来接收从子组件传递来的数据
// 子组件传递了几个数据,这里就有几个参数
receive(content){
this.content = content;
},
receive2(){
// console.log("子调父");
// ref进行标注子组件,然后实施调用
this.$refs.www.seachContent(this.content);
},
},
components: {
Side,
NewsRight
}
}
</script>
<style scoped>
.main{
height: 100%;
background: #ff6436;
}
</style>
10.NewsLeft.vue
<template>
<div>
<!-- 通过lable改变isCollapse的值-->
<!-- <el-radio-group v-model="isCollapse" style="margin-bottom: 20px">-->
<!-- <el-radio-button :label="false">expand</el-radio-button>-->
<!-- <el-radio-button :label="true">collapse</el-radio-button>-->
<!-- </el-radio-group>-->
<!--
default-active:默认点击
:collapse 是否折叠
el-menu是主目录
el-menu-item是一个目录下的元素
el-sub-menu是子目录
-->
<el-menu
default-active="2"
:collapse="isCollapse"
@open="handleOpen"
@close="handleClose"
>
<el-menu-item index="0" @click="changeState">
<el-icon><aim /></el-icon>
<!--伸展的时候在里面显示,折叠的时候在外面显示 #title是标题-->
<template #title>{{stateInfo}}</template>
</el-menu-item>
<el-menu-item index="{{index}}" v-for="(data, index) in datas" @click="see(data.url.split('=')[1])">
<el-icon><Document /></el-icon>
<template #title>
<div @click="see(data.url.split('=')[1])">{{data.name}}</div>
</template>
</el-menu-item>
</el-menu>
</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
import {
Location,
Document,
Menu as IconMenu,
Setting,
Aim
} from '@element-plus/icons'
export default {
name: 'Side',
props: ['contents'],
components: {
Location,
Document,
Setting,
IconMenu,
Aim
},
data(){
return{
stateInfo:"展开",
isCollapse:true,
datas:[],
}
},
setup() {
// ref("小黑"):生成变量,这是一个对象,需借助.value来赋值
// let isCollapse = ref(true);
const handleOpen = (key, keyPath) => {
// console.log(key, keyPath)
};
const handleClose = (key, keyPath) => {
// console.log(key, keyPath)
};
return {
handleOpen,
handleClose,
}
},
inject: ["out"],
methods:{
changeState() {
this.isCollapse=!this.isCollapse;
if(this.isCollapse){
this.stateInfo="展开";
}else {
this.stateInfo="收缩";
}
},
see (e) {
console.log("leftleft")
//定义函数,向父组件传值
this.$emit("up",e)
this.$emit("up2")
// this.$parent.out();
// this.out();
}
},
created: function () {
var self = this;
console.log(this.contents);
this.$axios.get(this.contents)
.then(function (res) {
console.log(res);
self.datas = res.data.data;
}).catch(function (error) { // 请求失败处理
console.log(error);
});
},
}
</script>
11. NewsRight
<template>
<main class="text-center">
<hr class="mt-2"/>
<div class="container" v-for="content in contents">
<div class="row mt-2 mb-2">
<!--右面5-->
<div class="col-md-3 text-center">
<img :src="content.imgUrl" style="width: 10rem;
height: 10rem">
</div>
<!--左面7-->
<div class="col-md-7">
<h2 class="featurette-heading">
<span class="text-muted">{{content.title}}</span>
</h2>
<p class="lead">
{{content.content}}
</p>
</div>
</div>
<hr/>
</div>
<!-- 页脚 -->
<footer class="fixed-bottom">
<!--右浮动-->
<p class="float-right"><a href="#app">Back to top</a></p>
<p>© 2017-2021 Company</p>
</footer>
</main>
</template>
<script>
export default {
data() {
return {
contents: []
}
},
methods: {
seachContent(condition) {
let self = this;
this.$axios.get('http://www.xlcode.top:8082/searchContent/' + condition)
.then(function (res) {
self.contents = res.data.data;
}).catch(function (error) { // 请求失败处理
console.log(error);
});
}
},
mounted:function(){
this.seachContent("realtime")
}
}
</script>