Vue基础
Vue简介
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。 [6] 与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用(SPA)提供驱动。
尤雨溪,前端框架Vue.js的作者,HTML5版Clear的打造人,独立开源开发者。曾就职于Google Creative Labs和Meteor Development Group。由于工作中大量接触开源的JavaScript项目,最后自己也走上了开源之路,现全职开发和维护Vue.js。
1、简化dom操作
2、前后端分离的开发
3、数据双向绑定
vscode
nodeJS: http://nodejs.cn/download/
vsstudio: https://code.visualstudio.com/
在文件夹中 cmd code . 则直接打开当前工程。
安装 auto rename tag插件。
安装code runner插件。
安装open in brower插件。
安装live server插件。
vetur 写vue必备插件
Vue 2 Snippets 写vue必备插件
axios插件
VueHelper vscode插件,vue,vue-router和vuex的代码提示
Path Intellisense 路径自动补全
Auto Close Tag 自动闭合标签
Beautify 格式化文件,保证正确的缩进
HTML CSS Support CSS提示插件
JavaScript (ES6) code snippets es6代码提示插件
VSCode Great Icons 给文件夹增加图标的插件
MVVM框架
model-view-viewmodel
Vue快速起步
1、添加vue的js文件
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
2、声明挂载点(操作的dom对象)
<div id="app">
{{name}} <!-- 差值表达式,输出vue中的数据 -->
</div>
3、声明vue对象
let vue = new Vue({
el:"#app", //绑定挂载点
data:{
name:"关羽" //声明属性(数据)
}
});
基础指令
1、v-text innerText text()
2、v-html innerHTML html()
3、v-on 事件 @
4、v-bind 属性绑定 :
<div id="app">
<p v-text="message"></p>
<span v-html="message2"></span>
<button v-on:click="abc()">btn</button>
<font v-bind:color="c">ok</font>
<input v-bind:value="val" >
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
message:"hello vue world!!!",
message2:"<font color='red'>no</font>",
c:"red",
val:"hello"
},
methods: {
abc(){
alert(123);
}
}
});
</script>
做了一个数量加减
<div id="app">
<button @click="jian()">-</button><input size="3" :value="count"><button @click="jia()">+</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
count:0
},
methods: {
jian(){
this.count--;
},
jia(){
this.count++;
}
}
});
</script>
事件修饰符
1、stop
当页面出现事件冒泡,而业务需要各自触发,在底层事件中添加修饰符stop,当该事件执行后,不再进行冒泡。
<div id="app">
<div v-on:click="a()" style="width: 600px; height: 600px; background-color: antiquewhite;">
<div v-on:click.stop="b()" style="width: 400px; height: 400px; background-color:blue;">
<button type="button" v-on:click.stop="c()">事件冒泡</button>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
methods: {
a(){
alert("a");
},
b(){
alert("b");
},
c(){
alert("c");
}
}
});
</script>
2、prevent
当触发事件的事件源有默认功能,通过prevent取消默认功能。
<div id="app">
<a @click="a()" href="https://www.baidu.com">百度</a>
<form action="index.html">
<button @click.prevent="a">submit</button>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
methods: {
a(){
alert("a");
}
}
});
</script>
3、capture
当有事件冒泡,被capture描述的事件会放在第一位执行,余下的冒泡继续执行
<div id="app">
<div v-on:click="a()" style="width: 600px; height: 600px; background-color: antiquewhite;">
<div v-on:click.capture="b()" style="width: 400px; height: 400px; background-color:blue;">
<button type="button" v-on:click="c()">事件冒泡</button>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
methods: {
a(){
alert("a");
},
b(){
alert("b");
},
c(){
alert("c");
}
}
});
</script>
4、once
该事件执行一次
<div id="app">
<a href="https://www.baidu.com" @click.prevent.once="a()">百度</a>
<button @click.once="a()">once</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
methods: {
a(){
alert("a");
}
}
});
</script>
v-model双向绑定
对Vue对象中数据进行修改,则所有展示该数据的位置都进行变化。
<div id="app">
<span>{{name}}</span>
<input v-model="name">
<select v-model="name">
<option>张无忌</option>
<option>张三丰</option>
<option>张翠山</option>
</select>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
name:"张三丰"
}
});
</script>
Vue绑定元素的class属性
1、class添加方式
<div id="app">
<button @click="red()">red</button>
<button @click="green()">green</button>
<button @click="blue()">blue</button>
<div id="div1" style="width: 400px; height: 400px;" v-bind:class="clazz">
</div>
</div>
<style>
.red{
background-color: red;
}
.green{
background-color: green;
}
.blue{
background-color: blue;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
clazz:"red"
},
methods: {
red(){
this.clazz = "red";
},
green(){
this.clazz = "green";
},
blue(){
this.clazz = "blue";
}
}
});
</script>
通过boolean值解决class是否添加
<div id="app">
<div id="div1" style="width: 400px; height: 400px;" :class="clazz">
</div>
</div>ji
<style>
.border{
border: 10px solid red;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
clazz:{"border":false}
}
});
</script>
class值可以是多个,按照数据结构放置
<div id="app">
<input type="radio" @click="border()">加边框
<input type="radio" @click="bg()">加背景
<div id="div1" style="width: 400px; height: 400px;" :class="clazz">
</div>
</div>ji
<style>
.border{
border: 10px solid red;
}
.bg{
background-color: rosybrown;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
clazz:[]
},
methods: {
border(){
this.clazz.push("border");
},
bg(){
this.clazz.push("bg");
}
}
});
</script>
可以通过三目运算添加class
2、style
直接在:style中编写样式json结构
可以在data中声明样式的变量,这个变量也可以是多个,用数组保存
<div id="app">
<!--
style属性添加内容时结构是width:400px
:style添加结构是{width:'400px'}
-->
<div id="div1" :style="{width:'400px',height:'400px',backgroundColor:'red'}">
</div>
<div id="div2" :style="styleObj">
</div>
<div id="div2" :style="[styleObj,styleObj2]">
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
styleObj:{width:'400px',height:'400px',backgroundColor:'blue'},
styleObj2:{border:'10px solid green'}
}
});
</script>
v-for
1、数组循环
2、对象循环
3、对象数组循环
<div id="app">
<ul>
<!--
1、循环数组时:
in前面可以加单参,就是值
in前面可以加双参,第一个是值,第二个是下标
-->
<li v-for="wujiang,index in wujiangs">{{index+1}},{{wujiang}}</li>
</ul>
<!--
2、循环对象
第一个是值
第二个是属性
第三个是下标
-->
<p v-for="x,y,z,i in wujiang1">{{x}}---{{y}}-----{{z}}</p>
<!--
3、循环对象数组
-->
<ul v-for="x in wujiangs2">
<li v-for="a in x">
{{a}}
</li>
</ul>
<!--
数据展示样例
-->
<table>
<tr>
<th>编号</th>
<th>姓名</th>
<th>武器</th>
</tr>
<tr v-for="wj,index in wujiangs2">
<th>{{index+1}}</th>
<th v-text="wj.name"></th>
<th v-text="wj.weapon"></th>
</tr>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
wujiangs:['黄忠','小乔','盾山'],
wujiang1:{
name:'小乔',
weapon:'扇子'
},
wujiangs2:[
{
name:'小乔',
weapon:'扇子'
},
{
name:'黄忠',
weapon:'大炮'
},
]
}
});
</script>
v-if、v-show
v-if和v-show都可以控制页面元素的显示与不显示
v-if对于不显示的元素,不生成。
v-show对于不显示的元素,生成并设置样式不可显
如果该元素一直不显示就使用v-if
如果该元素会根据状况一会显示一会不显示,则使用v-show
<div id="app">
<button v-if="permission.indexOf('delete')!=-1">删除</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
permission:"update,add"
}
});
</script>
Vue进阶
Vue全局过滤器
可以跨Vue使用,字符串格式化、日期格式化、金额格式化等等。
声明全局过滤器
//全局过滤器
//生成过滤器,通过静态方法filter,第一个参是过滤器名称,第二个是过滤器功能(函数)
Vue.filter("dateFormat", function(value){
let year = value.getFullYear();
let month = value.getMonth()+1;
let date = value.getDate();
return `${year}-${month}-${date}`;
});
使用过滤器
<div id="app">
{{birth|dateFormat}}
</div>
<div id="app2">
{{birth|dateFormat}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
//全局过滤器
//生成过滤器,通过静态方法filter,第一个参是过滤器名称,第二个是过滤器功能(函数)
Vue.filter("dateFormat", function(value){
let year = value.getFullYear();
let month = value.getMonth()+1;
let date = value.getDate();
return `${year}-${month}-${date}`;
});
let vue = new Vue({
el:"#app",
data:{
birth:new Date()
}
});
let vue2 = new Vue({
el:"#app2",
data:{
birth:new Date()
}
});
</script>
Vue私有过滤器
在Vue对象中声明的过滤器,只能在当前Vue对象中使用,不能跨Vue使用。
<div id="app">
{{salary|numFormat}}
</div>
<div id="app2">
{{comm|numFormat}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
salary:30000 //30,000
},
filters: {
"numFormat":function(value){
value+="";
console.log(value.length);
let start = value.length-3;
console.log(start);
let front = value.substring(0,start);
console.log("front:"+front);
let back = value.substring(start);
return `${front},${back}`;
}
}
});
let vue2 = new Vue({
el:"#app2",
data:{
comm:5300 //5,300
}
});
</script>
按键修饰符
获得键盘事件
不需要在事件处理中判断点的是哪个键
直接使用按键修饰符即可。
@keyup.enter="add()" //在输入框中添加该事件及按键修饰符等同于点按钮
<div id="app">
<form>
uname<input name="uname" id="uname" v-model="user.uname">
upwd<input name="upwd" id="upwd" v-model="user.upwd" @keyup.enter="add()">
<button type="button" @click="add()">add</button>
</form>
<table width="600" border="1">
<tr>
<th>编号</th>
<th>用户名</th>
<th>密码</th>
</tr>
<tr v-for="user,index in userList">
<th>{{index+1}}</th>
<th>{{user.uname}}</th>
<th>{{user.upwd}}</th>
</tr>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
user:{
uname:"",
upwd:""
},
userList:[
{"uname":"admin","upwd":"123"},
{"uname":"andy","upwd":"456"}
]
},
methods: {
add(){
this.userList.push(this.user);
}
}
});
</script>
Vue自定义指令
v-text、v-html
当前需要新的指令完成一定的功能
例如:将焦点直接设置某个控件上
全局自定义指令和局部自定义指令
<div id="app">
<input name="n1" >
<input name="n2" v-focus >
<input name="n3" >
</div>
<div id="app2">
<input name="n1" >
<input name="n2" >
<input name="n3" v-focus >
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
//定义全局的自定义指令
//
// Vue.directive("focus",{
// inserted:function(dom){
// dom.style.backgroundColor='red';
// dom.focus();
// }
// });
let vue = new Vue({
el:"#app",
directives: {
"focus":{
inserted:function(dom){
dom.style.backgroundColor="green";
dom.focus();
}
}
}
});
let vue2 = new Vue({
el:"#app2"
});
</script>
Vue组件的生命周期
<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/java/panfeng/20210507143352.png" style="zoom: 80%;" />
1、初始化数据
beforeCreate() //这时Vue还没有初始化数据,没有el、data等等,只有默认事件和vue生命周期
created() //data、methods都已经初始化了,这时还没有el
2、挂载
beforeMount() //获得el,但是el的数据没有添加上
mounted() //将数据与模板整合。
3、修改数据
beforeUpdate() //修改数据之前方法
updated() //修改数据之后的方法
4、销毁
this.$destroy();
完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器。
触发 beforeDestroy
和 destroyed
的钩子。
beforeDestroy() //销毁之前,还可以使用vue的数据
destroy(); //销毁之后,所有vue数据不可用。
<div id="app">
{{message}}
<input v-bind:value="message">
<button @click="message='数据修改了'">修改message数据</button>
<button @click="clear()">clear</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
message:"hello vue life!!"
},
methods: {
clear(){
this.$destroy();
}
},
//编写钩子函数 在创建、挂载、修改、销毁4个点分别2个钩子函数
beforeCreate () {
console.log(this.$el);
console.log(this.$data);
console.log(this.message);
},
created () {
console.log(this.$el);
console.log(this.$data);
console.log(this.message);
},
beforeMount () {
console.log(this.$el);
console.log(this.$data);
console.log(this.message);
},
mounted () {
console.log(this.$el);
console.log(this.$data);
console.log(this.message);
},
//this.$el的数据已经解析
beforeUpdate () {
console.log(this.$el);
let div = document.getElementById("app");
console.log(div.innerHTML);
console.log(this.message);
},
updated () {
console.log(this.$el);
let div = document.getElementById("app");
console.log(div.innerHTML);
console.log(this.message);
},
//虽然这里的数据还可以看到,但是所有功能已经不存在了。
beforeDestroy () {
console.log("------------------");
console.log(this.$el);
let div = document.getElementById("app");
console.log(div.innerHTML);
console.log(this.message);
},
destroyed () {
console.log(this.$el);
let div = document.getElementById("app");
console.log(div.innerHTML);
console.log(this.message);
}
});
</script>
Computed和Watch
1、computed计算列
结构类似于方法
computed: {
result:function(){
return parseInt(this.num1)+parseInt(this.num2);
}
}
在需要展示的地方,放置计算列的名称
当计算列中的属性值发生变化,则重新计算并加载到页面
2、watch
<div id="app">
<input v-model="age" >
{{age}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
age:0
},
watch: {
age(newVal,oldVal){
this.age = newVal.replace(/[^\d]/g,'');
}
}
});
</script>
前后端分离案例
1、通过Springboot搭建Controller接口
package com.woniu.controller;
import com.woniu.service.EmpService;
import com.woniu.util.ResultVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* @Author: Panda
* @Date: 2021/5/8 09:32
* @Description:
*/
@RestController //@ResponseBody和@Controller 所有handler返回json数据
@RequestMapping("emp")
public class EmpController {
@Autowired
private EmpService empService;
@GetMapping //@RequestMapping(method=RequestMethod.GET)
public ResultVO list(){
return ResultVO.Result(200,"员工列表查询成功",empService.findByPage());
}
}
2、配置跨域
package com.woniu.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
/**
* @Author: Panda
* @Date: 2021/5/8 09:44
* @Description:
*/
@Configuration
public class CORSConfig extends WebMvcConfigurationSupport {
@Override
protected void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST","PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.exposedHeaders("access-control-allow-headers",
"access-control-allow-methods",
"access-control-allow-origin",
"access-control-max-age",
"X-Frame-Options")
.allowCredentials(false).maxAge(3600);
super.addCorsMappings(registry);
}
}
3、编写vue页面
添加axios的js文件
<div id="app">
<table width="1000" border="1" align="center">
<caption><h2>员工管理</h2></caption>
<tr>
<th>序号</th>
<th>姓名</th>
<th>职位</th>
<th>上级</th>
<th>雇佣日期</th>
<th>工资</th>
<th>奖金</th>
<th>部门</th>
<th>编辑</th>
<th>删除</th>
</tr>
<tr v-for="emp,index in empList">
<th>{{index+1}}</th>
<th>{{emp.ename}}</th>
<th>{{emp.job}}</th>
<th>{{emp.mgr}}</th>
<th>{{emp.hiredate}}</th>
<th>{{emp.sal|numFormat}}</th>
<th>{{emp.comm|numFormat}}</th>
<th>{{emp.deptno}}</th>
<th>{{emp.empno}}</th>
<th>{{emp.empno}}</th>
</tr>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
//发送ajax请求,在vue中是用axios
Vue.filter("numFormat",function(value){
if(value==null||value==""){
return "";
}
value=value+"";
if(value.length<=3){
return value;
}
let start = value.length-3;
return value.substring(0,start)+","+value.substring(start);
});
let vm = new Vue({
el:"#app",
data:{
empList:null
},
mounted () {
this.list();
},
methods: {
list(){
let _this = this;
axios.get("http://localhost:8080/emp")
.then(function(response){
console.log(response.data.data);
_this.empList = response.data.data;
console.log(this);
})
.catch(function(error){
consolse.log(error);
})
}
}
});
</script>
日期类型需要配置格式
axios({
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
method: 'POST',
url: 'http://localhost:9000/save',
params:{
uid: this.uid,
uname: this.uname,
upass: this.upass
},
})
.then((res) => {
this.show();
})
.catch((err) => {
console.error(err);
})
axios发请求的基本语法:
axios({
url: '路径', // 这个路径中可以包含params或query参数
method: 'get/post/put/delete',
params: {}, // 包含query参数的对象,问号后面的参数
data: {}, // 包含请求体参数的对象
})
axios.get(url, {配置}) // {params: {id: 1}}
axios.delete(url, {配置})
axios.post(url, data数据对象)
axios.put(url, data数据对象)
使用axios发ajax请求携带参数:
params参数: 只能拼在路径中: /admin/product/baseTrademark/delete/1
query参数:
拼在路径中的?后面: /admin/product/baseTrademark?id=1
通过params配置来指定: axios({params: {id: 1}})
请求体参数:
通过data配置或post()/put()的第二个参数指定
Vue组件
创建Vue组件的三种方式
Component是一个自定义控件,相当于自定义标签,将多个标签组合成一个模块,可以在需要的地方进行添加
<div id="app">
<com3></com3>
<com4></com4>
</div>
<div id="app2">
<com3></com3>
<com4></com4>
</div>
<!--
声明模板
如果有多个标签,这时模板的内容只展示第一个标签
在多个标签的外层添加一个根标签
-->
<template id="temp3">
<div>
<h2>第三种组件</h2>
<h3>第三种组件2</h3>
</div>
</template>
<template id="temp4">
<div>
<font color='red'>组件4</font>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
//声明一个添加表单
//声明全局组件,所有的Vue都可以使用
//1、先使用extend声明模板、将模板注册为全局组件
//声明模板
// let temp1 = Vue.extend({
// template:`<form>
// uname<input />
// upwd<input />
// <button>add</button>
// </form>`
// });
// //将模板注册为组件
// //"com1"就是自定义了一个标签名
// Vue.component("com1",temp1);
//2、直接将模板内容注册为全局组件
// Vue.component("com2",{
// template:`<h1>组件2</h1>`
// });
//编写模板内容太麻烦
//3、在html代码直接编写模板,将模板注册到组件中
Vue.component("com3",{
template: "#temp3" //#temp3对应html中声明的模板
});
let vue = new Vue({
el:"#app",
//声明局部组件,只能在当前Vue中使用
components: {
"com4":{
template:"#temp4"
}
}
});
let vue2 = new Vue({
el:"#app2"
});
</script>
在组件中可以声明属性和方法
<div id="app">
<component1></component1>
</div>
<template id="template1">
<div>
<h2>{{messageCom}}</h2>
<button @click="cm()">changeMessage</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
message:"这是Vue中data" //组件无法直接访问Vue中的data
},
components: {
"component1":{
template:"#template1",
data(){ //组件中的data必须按照方法声明,必须有return
return{
messageCom:"这是组件中的data"
}
},
methods: {
cm(){
console.log("这是组件中的cm方法");
this.messageCom="组件中的cm方法改变了我";
}
}
}
},
methods: {
cm(){ //组件不能直接访问Vue中的方法
console.log("这是Vue中的cm方法");
}
}
});
</script>
组件的切换
在Vue挂载点上声明<component :is="组件名">
通过按钮或者超链接改变组件名称,从而达到切换组件的功能。
<div id="app">
<a href="#" @click.prevent="comName='logincom'">login</a>
<a href="#" @click.prevent="comName='regcom'">reg</a>
<!-- <logincom v-if="showLogin"></logincom>
<regcom v-if="!showLogin"></regcom> -->
<!--
component标签作为组件的载体
:is=组件名称
-->
<component :is="comName"></component>
</div>
<template id="login">
<div>
<h3>用户登录</h3>
<form>
uname<input type="text">
upwd<input type="text">
<button>login</button>
</form>
</div>
</template>
<template id="reg">
<div>
<h3>用户注册</h3>
<form>
uname<input type="text">
upwd<input type="text">
upwd<input type="text">
<button>reg</button>
</form>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
showLogin: false,
comName: "logincom"
},
components: {
"logincom":{
template:"#login"
},
"regcom":{
template:"#reg"
}
}
});
</script>
父子组件相互访问属性和方法
1、子组件访问父组件的data
父组件通过子组件的属性props将父组件中的data传递到子组件中
2、子组件访问父组件的method
父组件通过在子组件上声明事件,将父组件的方法放到事件里,子组件通过this.$emit("事件名",参数)
<div id="app">
<myfont v-bind:color="color" @abc="m1"></myfont> <!-- 如果m1方法有参数,则省略() -->
</div>
<template id="template1">
<div>
<font v-bind:color="color">abc</font>
<button @click="m2()">按钮</button>
</div>
</template>
<!-- 假设font标签就是自定义的,那么怎么改变字的颜色,需要在声明该标签时,声明对应的属性 -->
<!--
子组件访问父组件的data
1、定义子组件
2、定义该组件的属性
3、在父组件中声明子组件
4、绑定子组件的属性,这时将父组件的data数据通过属性传递到子组件中
子组件访问父组件的方法
1、定义子组件
2、定义该组件的方法
3、在父组件中声明子组件,并声明一个事件调用父组件的方法
4、在子组件中使用this.$emit("事件名")
5、如果父组件的方法带参数,在this.$emit("事件名",参数)即可
父组件访问子组件的data和method
-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
color:"red"
},
methods: {
m1(val){
alert(val);
}
},
components: {
"myfont":{
template:"#template1",
props:['color'],
methods: {
m2(){
//通过子组件的方法调用父组件的方法
this.$emit("abc","this is a message");
}
}
}
}
});
</script>
3、父组件访问子组件的data和method
在子组件中声明ref,通过this.$refs.refVal.data|method
<div id="app">
<com ref="refName"></com>
<button @click="m()">btn</button>
</div>
<template id="template1">
<div>
</div>
</template>
<!--
父组件访问子组件的data和method
-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
data:{
color:"red"
},
methods: {
m(){
console.log(this.$refs.refName.message);
this.$refs.refName.m1();
}
},
components: {
"com":{
template:"#template1",
data(){
return{
message:"子组件的data"
}
},
methods: {
m1(){
console.log("子组件的method");
}
}
}
}
});
</script>
Vue如何获取DOM元素
使用两种方式获取dom元素
1、document.getElementById()提供的方法获取,可以获取当前页面中所有的有id的dom节点
2、通过ref获取,只能获取当前访问的dom节点
<div id="app">
<com ref="r3"></com>
<input ref="r2" value="456">
<button @click="m2()">btn2</button>
</div>
<template id="template1">
<div>
<input ref="r1" value="123" id="r1">
<button @click="m()">btn</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vue = new Vue({
el:"#app",
methods: {
m2(){
// console.log(this.$refs.r1);
// console.log(this.$refs.r2);
this.$refs.r2.style.backgroundColor='red';
console.log(document.getElementById("r1"));
}
},
components: {
"com":{
template:"#template1",
methods: {
m(){
console.log(this.$refs.r1);
console.log(this.$refs.r2);
}
}
}
}
});
</script>
Vue路由
Vue路由
声明组件就是模块化开发,通过链接进行组件切换
<component>和组件名
添加vue-router.js
<script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
需要在vue.js后添加
1、声明所有的组件
let list = Vue.component("list",{
template:"#list"
});
let list = {
template:"#list"
};
2、声明路由,将所有组件对应访问路径
let router2 = new VueRouter({
routes:[
{component:list,path:"/list"},
{component:add,path:"/add"}
]
});
3、声明路由展示标签
<router-view></router-view>
4、声明链接进行切换
<a href="#/list">list</a>
<a href="#/add">add</a>
链接的位置需要加#,等同于锚点链接
5、可以把链接改成<router-link>
<router-link to="/list">list</router-link>
<router-link to="/add">add</router-link>
链接的位置不需要加#
传参方式:
a、?绑定传参 this.$route.query.参数名
b、rest传参 this.$route.params.参数名(该参数名需在路由中配置,/:参数名)
<router-link to="/list?id=1">list</router-link>
<router-link to="/add/123">add</router-link>
let list = {
template:"#list",
methods: {
m1(){
console.log(this.$route);
console.log(this.$route.query);
console.log(this.$route.query.id);
}
}
};
let add = {
template:"#add",
methods: {
m2(){
console.log(this.$route);
console.log(this.$route.params);
console.log(this.$route.params.deptno);
}
}
};
Vue二级路由
当页面中有多个模块的组件,将这些组件分别管理路由
需要添加模块的根路由,在根路由中添加子路由
在根组件中添加子组件的路由和展示。
在根组件中切换子组件
<div id="app">
<router-link to="/emp">员工管理</router-link>
<router-link to="/user">用户管理</router-link>
<router-view></router-view>
</div>
<template id="empList">
<div>
<h2>员工列表页</h2>
<router-link to="/add">员工添加</router-link>
<router-view></router-view>
</div>
</template>
<template id="empAdd">
<div>
<h2>员工添加页</h2>
</div>
</template>
<template id="userList">
<div>
<h2>用户列表页</h2>
<router-link to="/add">用户添加</router-link>
<router-view></router-view>
</div>
</template>
<template id="userAdd">
<div>
<h2>用户添加页</h2>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
<script>
let empList = {
template:"#empList"
}
let empAdd = {
template:"#empAdd"
}
let userList = {
template:"#userList"
}
let userAdd = {
template:"#userAdd"
}
let router = new VueRouter({
routes:[
{
component:empList,
path:"/emp",
children:[
{component:empAdd,path:"/add"},
]
},
{
component:userList,
path:"/user",
children:[
{component:userAdd,path:"/add"}
]
}
]
});
let vue = new Vue({
el:"#app",
router //router:router
});
</script>
Vue命名路由
命令路由
命名路由方便调用,并可以直接按照rest传值
<div id="app">
<router-link :to="{'name':'emp',params:{'id':1001}}">员工管理</router-link>
<router-view></router-view>
</div>
<template id="empList">
<div>
<h2>员工列表页</h2>
<button @click="method1()">btn</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
<script>
let empList = {
template:"#empList",
methods: {
method1(){
console.log(this.$route.params.id);
}
}
}
let router = new VueRouter({
routes:[
{
component:empList,
path:"/emp/:id",
name:"emp"
}
]
});
let vue = new Vue({
el:"#app",
router //router:router
});
</script>
命名视图
<div id="app">
<router-view></router-view>
<router-view name="nav"></router-view>
<router-view name="main"></router-view>
</div>
<template id="logo">
<div style="width: 1000px; height: 150px; background-color: antiquewhite;">
<h2>标题</h2>
</div>
</template>
<template id="nav">
<div style="width: 150px; height: 700px; background-color: chartreuse; float: left;">
<h2>导航</h2>
</div>
</template>
<template id="main">
<div style="width: 850px; height: 700px; background-color: coral; float: left;">
<h2>主界面</h2>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
<script>
let logo = {
template:"#logo"
}
let nav = {
template:"#nav"
}
let main = {
template:"#main"
}
let router = new VueRouter({
routes:[
{
path:"/",
components: {
default:logo,
nav:nav,
main:main
}
}
]
});
let vue = new Vue({
el:"#app",
router //router:router
});
</script>
守卫路由
也称为导航守卫
全局前置守卫router.beforeEach(to,from,next)
路由守卫
组件守卫
<div id="app">
<router-link to="/login">login</router-link>
<router-link to="/list">list</router-link>
<router-view ></router-view>
</div>
<template id="list">
<div>
<h2>list</h2>
</div>
</template>
<template id="login">
<div>
<h2>login</h2>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
<script>
let list = {
template:"#list"
}
let login = {
template:"#login"
}
let router = new VueRouter({
routes:[
{
path:"/",
component:login
},
{
path:"/list",
component:list
},
{
path:"/login",
component:login
}
]
});
//全局前置守卫
router.beforeEach((to, from, next) => {
//通过Vuex进行共享数据的存储,所有的组件都可以访问到
if(to.path=="/login"){
next();
}
});
let vue = new Vue({
el:"#app",
router //router:router
});
</script>
完整的导航解析流程
导航被触发。
在失活的组件里调用 beforeRouteLeave 守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
在路由配置里调用 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。