vue
通过官方文档进行学习
痛点(html+css+js)
- webapp里的文件会越来越多,规模越来越庞大,后台有MVC五层框架非常规范,而前端页面比较繁杂
- 业务只停留在按照模块划分,属于单页面开发,且页面之间要通过request或者session来传数据,页面相互间的关系很弱,页面零散
- 无法让前后端完全独立演进
基本概念
- Vue是一个基于JavaScript框架的前端框架
- 是一个创建前端单页面应用的Web应用框架
- 开发一套代码,可以跨平台使用,电脑端和手机端同时使用(uniapp),windows和ios同时使用
- 实现不同组件间的多级联动,增强界面的交互性
基础案例分析
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- vue渲染及操作区 -->
<!-- {{}}差值表达式 ,内部的内容是一个表达式-->
<h1 align="center">欢迎注册{{userName}}{{password}}</h1>
<table align="center">
<tr><td>用户名:</td><td><input type="text" v-model="userName"/></td></tr>
<!-- 两者绑定同一个变量password v-model实现数据的双向绑定,变量值改变组件value改变,组件value改变变量值也改变-->
<tr><td>密码:</td><td><input type="password" v-model="password"/></td></tr>
<tr><td>确认密码:</td><td><input type="password" v-model="password"/></td></tr>
<tr><td></td><td><input type="button" v-model="userName" v-on:click="doLogin"/></td></tr>
</table>
</div>
</body>
<script type="text/javascript">
var vm=new Vue({ //vue框架的入口,构造一个vue对象,并且传入一个对象参数
el:"#app", //挂载界面(DOM)元素,托管这个元素内部的所有内容
data:{ //data中的数据跟el属性是同级的,直接vm.msg进行访问,或者vm.$data.msg
userName:"", //$+属性名表示的是vue的内置属性
password:"",
count:1
},
methods:{
doLogin:function(){
//this表示vue对象,避免重名的变量
alert("用户名:"+this.userName+" 密码:"+this.password);
}
}
})
</script>
</html>
页面不需要刷新就能更新数据,vue后台有一套机制来帮我们更新DOM,虚拟DOM会先按照自己的规则解析浏览器不认识的自定义组件或者v-model这种元素的属性,解析成html超文本的代码,最后再同步到DOM上
Data中的数据可以通过后台数据或者Ajax异步请求传过来,就可以实现前后端的数据交互了
常用指令
v-model-------为元素绑定属性,双向绑定
v-bind----------为元素绑定属性,单向绑定,只能获取来自于全局属性的值
v-if -------------如果为真就显示组件(v-else v-else-if),否则html中直接没有该组件(代码),可多组件切换
v-show--------修改css样式来决定组件是否展示,display:none,只能用于单组件是否显示
v-for -----------循环展示多个组件(如表格中的行数据)
v-on------------为元素绑定事件
vue生命周期
- 想知道vue到底在背后偷偷摸摸干了什么
- 想参与到vue的生命周期中,做一些我们要做的事情
- 每个生命周期都会提供一个钩子方法
组件
一个大的区别:父组件的data是一个对象,子组件的data是方法,如果子组件的data也是对象会指向统计的子组件和父组件的data域,导致数据污染
错误方式:
正确方式:
组件案例
组件注册方式分为全局注册和局部注册
全局注册:程序一开始就初始化,会消耗大量资源,但是是被其他组件共享访问的
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 使用子 组件 -->
<my-login ></my-login>
</div>
<script type="text/javascript">
//全局注册
Vue.component("my-login",{
data:function(){ //定义子组件自己的属性
return {
userName:"admin",
password:"123"
}
},
methods:{ //定义子组件自己的方法
doLogin:function(){
//this表示vue对象,避免重名的变量
alert("用户名:"+this.userName+" 密码:"+this.password);
}
},
//template表示这个组件将来要显示的内容
//在整个组件树上都是通过div来模块化的,最外层需要加一个div
//如果只有一行就可以用单引号'',如果多行用``
//子组件中的v-model找的数据值和v-on要绑定的方法只能在子组件的data域和methods中找,上面那个
template:`<div><h1 align="center">欢迎注册</h1>
<table align="center">
<tr><td>用户名:</td><td><input type="text" v-model="userName"/></td></tr>
<tr><td>密码:</td><td><input type="password" v-model="password"/></td></tr>
<tr><td>确认密码:</td><td><input type="password" v-model="password"/></td></tr>
<tr><td></td><td><input type="button" v-model="userName" v-on:click="doLogin"/></td></tr>
</table></div>`
})
//全局父组件
var vm=new Vue({
el:"#app",
data:{
// userName:"admin",
// password:"123"
}
})
</script>
</body>
</html>
局部注册:当一个组件用到的时候才初始化
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 使用子组件 -->
<!-- 命名方式是固定的,这样写才能解析 -->
<my-button><button>登录</button></my-button>
<my-button>注册</my-button>
</div>
<script type="text/javascript">
//局部注册
let MyButton = {
data:function(){ //定义子组件自己的属性
return {
}
},
//组件内部传的值在template中用slot槽位进行接收,可以灵活接收这个信息展示的内容
template:'<div><slot></slot></div>'
}
//全局父组件
var vm=new Vue({
el:"#app",
data:{
},
methods:{},
components:{
MyButton //当做一个变量去找
}
})
</script>
</body>
</html>
组件传值
父向子传值
通过v-bind个子组件的某个属性进行绑定,绑定上父组件的某个属性,只不过从父组件传来的属性跟自己本身的属性还是有一定的差别,所以要拿出来放在props内置属性中,但是也跟子组件自己本身的属性是一样的用法
通过父组件向子组件传值的方式,可以实现一个模板展示不同的数据,实现模板的复用
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 一个模板动态复用,父组件传入的数据不同 -->
<my-login v-bind:value="value1"></my-login>
<my-login v-bind:value="value2"></my-login>
<my-login v-bind:value="value3"></my-login>
<my-login v-bind:value="value4"></my-login>
</div>
<script type="text/javascript">
//全局注册
Vue.component("my-login",{
props:['value','title','lable'], //接收从父组件传过来的属性,同时也作为自己的属性,可以通过差值表达式获得
data:function(){ //定义子组件自己的属性
return {
userName:"admin",
password:"123"
}
},
template:`<div><h1 align="center">{{value}}</h1>
<table align="center">
<tr><td>用户名:</td><td><input type="text" v-model="userName"/></td></tr>
<tr><td>密码:</td><td><input type="password" v-model="password"/></td></tr>
<tr><td>确认密码:</td><td><input type="password" v-model="password"/></td></tr>
<tr><td></td><td><input type="button" v-model="userName" /></td></tr>
</table></div>`
})
var vm=new Vue({
el:"#app",
data:{
// userName:"admin",
// password:"123"
value1:"欢迎登录",
value2:"欢迎注册",
value3:"新增用户",
value4:"新增订单"
}
})
</script>
</body>
</html>
子向父传值
思路就是用v-on:不断监听子组件的一个方法或者属性,监听方法是否有提交给父组件数据,监听属性就是监听子组件的属性是否改变,然后指定父组件的一个方法来接收传来的数据
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 监听子组件messge属性的变化,并将该属性传给父组件的getMassage函数进行处理,该函数默认接受一个事件,事件就是子组件传来的属性:getMassage(event) -->
<!-- 这块儿与普通的赋值有点不同,并不是把子组件的数据赋值给父组件的某个方法,但是肯定要遵循一点:右边双引号内的方法肯定是父组件methods里的 -->
<my-login v-bind:value="value1" v-on:message="getMassage"></my-login>
</div>
<script type="text/javascript">
//全局注册
Vue.component("my-login",{
data:function(){ //定义子组件自己的属性
return {
userName:"admin",
password:"123"
}
},
methods:{
doLogin:function(){
//alert("进来了");
//抛出数据
this.$emit("message",{userName:this.userName,password:this.password});
},
},
template:`<div><h1 align="center">{{value}}</h1>
<table align="center">
<tr><td>用户名:</td><td><input type="text" v-model="userName"/></td></tr>
<tr><td>密码:</td><td><input type="password" v-model="password"/></td></tr>
<tr><td>确认密码:</td><td><input type="password" v-model="password"/></td></tr>
<tr><td></td><td><input type="button" v-model="userName" v-on:click="doLogin"/></td></tr>
</table></div>`
})
var vm=new Vue({
el:"#app",
data:{
value1:"欢迎登录",
},
methods:{
getMassage:function(e)
{
alert("子组件传值:用户名:"+e.userName+" 密码:"+e.password);
}
}
})
</script>
</body>
</html>
同级组件传值
- 将父组件作为中间商,先从一个子组件将值传给父组件,然后父组件再传给另一个子组件,实现同级组件之间的传值操作
- 用路由的方式实现同级组件传值,见下方路由传值板块
路由
进行平行组件之间传值
控制页面组件的跳转
Routes:路由列表 描述路径信息,路由器上的链路的信息,是一个数组
var routes=[{path:‘/’,component:IndexComponent}]
Router:路由上下文 编程时要进行触发的路由,将来所要跳转的页面的路由的主对象,直接触发路径主动跳转 this.$router.push(“/index”);
Route: 路径发生变化时用来描述路径,当前的路由信息
router进行单页面开发:(在同一个页面中实现组件的切换和组件间的传值)
组件的切换
声明式组件切换:通过(组件)和(超链接)标签来触发路由链表中的某一条路径
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!--不知道为啥vue.js要写在前面 -->
<script src="js/vue.js" ></script>
<script src="js/vue-router.js"></script>
</head>
<body>
<div id="app">
<!-- 两个声明式的路由组件 -->
<!-- html中以超链接形式展示 -->
<!-- 由于三个组件不是完整的html文档,点击超链接后跳转到#/、#/login或者#/register,#/就表示路由但是无法显示页面 -->
<router-link to="/">主页</router-link>
<router-link to="/login">登录</router-link>
<router-link to="/register">注册</router-link>
<hr>
<!-- 如果我们想让三个组件显示在当前位置(当前这个div),就用router-view来占位 ,点击某个超链接下面的占位符就显示哪个组件-->
<!-- 相当于一个槽位来占位置 -->
<router-view></router-view>
<hr>
</div>
<script type="text/javascript">
//创建三个路由组件
var IndexComponent={template:`<div>主界面</div>`};
var LoginComponent={template:`<div>登录界面</div>`};
var RegisterComponent={template:`<div>注册界面</div>`};
//创建路由列表
var routes=[
{path:'/',component:IndexComponent}, //将来可以在这儿(路由列表)用新的标记携带组件中的数据(静态数据)
{path:'/login',component:LoginComponent}, //或者在路由的链路上用预占位符来传递数据
{path:'/register',component:RegisterComponent}
];
//创建路由对象
//括号里两个如果一致可以直接写一个
var router =new VueRouter({routes:routes});
var vm=new Vue({
el:"#app",
router,
data:{
}
});
</script>
</body>
</html>
组件的传值
-
通过页面切换的时候通过动态路由的方式:+属性来传参(通过路径传参)
url形式: -
通过router来跳转传参,编程式的传参方式
methods:{
doLogin:function () {
//往后台传参,发起异步请求 (原生你的异步请求方式)
//this.$http.get()
//路径跳转 --页面跳转,找路径对应的组件并显示
this.$router.push("/index");
//路径跳转并通过Query传参 --这儿的数据是通过http请求获取的数据,再携带数据进行跳转
this.$router.push({path:"/index",query:{loginState:'true'}})
// //路径跳转并通过params传参(界面能跳,但是拿不到参数值,不使用),可以理解为与动态路由方式冲突了
// this.$router.push({path:"/index",params:{loginState:'true'}})
//组件跳转并通过Query传参
this.$router.push({name:"/Index",query:{loginState:'true'}})
//组件跳转并通过Params传参
this.$router.push({name:"/Index",params:{loginState:'true'}})
this.$router.push({path:"/index?username=123",query:{loginState:'true'}})
}
}
url形式:
可以看出编程式传递参数url的最终表现形式是和后台的发起请求的url是一样的,因此也可以直接像后台发起请求那样写参数
-
组件内部的获取参数的方式是一样的 ,通过差值表达式 {{}} 来获取路径中的参数,{{}}即可以获取data中的数据,也可以获取路径中的参数
{{this.$route.params.userName}} 传参的时候必须使用params进行传参(:key),这种方式传过来的参数也必须使用params来接受,否则接收不到{{this.$route.query.loginState}} 处理编程式跳转页面的传参
vue脚手架
也是可以通过官网学习
用脚手架工具快速地实施项目的作业,基于命令行的方式,
将前端进行规范化,webpack(与maven类似)将前端的依赖管理起来(与后端的思路类似),将依赖关系进行优化和压缩,依赖调用更加顺畅,另外还可以发布构建的项目,webpack依赖于npm存在,npm是nodejs软件包的管理工具
VUE环境配置:
//配置NPM包下载及存储位置
npm config set prefix “D:\Program Files\nodejs\node_global”
npm config set cache “D:\Program Files\nodejs\node_cache”
// 配置淘宝镜像位置
npm config set register https://registry.npm.taobao.org
//安装VUE2.X版本
npm install -g vue-cli
//如果安装错误可进行卸载
npm uninstall -g @vue/cli
//安装WebPack打包工具
npm install -g webpack
//创建VUE项目并使用WebPack进行打包发布
vue init webpack vue-demo
以上的命令都需要在管理员模式下运行,也可以自己去开启权限(我是每次以管理员身份运行cmd)
创建的项目结构:
idea中运行vue项目
-
安装vue.js插件,但是2020版的好像找不到插件
解决idea在plugins中搜索不到插件 -
创建vue项目
-
配置npm运行项目
-
如果把前后端的项目都配置在一个项目中,同时发布前端项目和后端项目,二者默认端口号都是8080,对导致前后端端口冲突,所以需要修改一下端口号
-
前端一个.vue文件就相当于后端的一个.java文件,每个.vue文件就是某个界面或者某个区域或者某个组件,最好是按照业务来将.vue文件进行归纳,创建不同的文件夹
element-ui
一些需要注意的知识点:
- element-ui的布局为流式布局
- offset:相对于前一个组件进行偏移的格子个数
- 具体的elment-ui布局组件是行元素,比如el-header el-aside ,前后元素是会换行的,如果想在一行中展示需要给第二个组件包裹一层el-container,这时就会紧贴前一个组件的右边,el-container也用来装多个组件进行布局
- element-ui最主要的是页面布局,如果页面有东西显示不出来,或者有问题,首先看看布局问题