指令
知识点
- v-model修饰符 trim number lazy
v-model修饰符 trim number lazy
v-for
可以遍历对象 数组 字符串 数字
v-pre 不编译里面的东西
v-cloak
加v-cloak时 页面没加载完成会带有v-cloak 加载完毕就变没
前面引入js加载慢
那么页面就会提前显示{{}}
很丑
加v-cloak时 页面没加载完成会带有v-cloak 加载完毕就变没
则自己添加css样式
*[v-cloak]{
display:none;
}
事件
修饰符 .stop冒泡 .once单次 .prevent默认事件 .self只处理自己的事件 .capture
.native原生事件(组件里用的)
常用特性知识
- 计算属性有缓存(依赖data种的数据进行缓存),方法没有缓存。
- v-model修饰符 trim number lazy
样式绑定
常规
数组先写到data里面在写到数组 切换让this.对应的值变为空串
对象对应false和true 切换之间改布尔值
<template>
<div>
<button @click.prevent="handle1">切换</button>
<button @click.prevent="handle2">切换2</button>
<span :class="{color:key1 , bgcolor:key2}">容器</span>
<span :class="[color,bgcolor]">容器</span>
</div>
</template>
<script>
export default {
data() {
return {
key1: true,
key2: true,
color:"color",
bgcolor:"bgcolor"
};
},
methods: {
handle1() {
this.key1 = !this.key1;
},
handle2() {
this.key2 = !this.key2;
}
}
};
</script>
<style>
.size {
width: 100px;
height: 100px;
}
.bgcolor {
background-color: aqua;
}
.color {
color: red;
}
</style>
- 对象绑定数组绑定结合使用
<span :class="[color,bgcolor,{test:isTest}]">容器</span>
和正常使用无异
- class绑定的值简化写法
<div :class="arrClasses">简化写法</div>
定义一个data值 如果需要操作类那么就用数组api改数组
arrClasses:["color","bgcolor"]
————————————————————————————————————————————————————————————————————————
<div :class="objClasses">简化对象写法</div>
</div>
定义一个data值
objClasses:{ 如果需要操作类那么就改对象 this.objClasses.color = false
color:true,
bgcolor:true
}
- 默认的class如何处理
<div class="default" :class="objClasses">默认</div>
默认的会保留共存不会覆盖
style样式处理
<template>
<div>
<div :style="{border:borderSytle,width:widthStyle,height:heightSytyle}">style</div>
<button @click="handle">切换</button>
<div :style="objStyles">第二种写法</div>
</div>
</template>
____________________________________________________________________
<script>
export default {
data() {
return {
borderSytle: "1px solid blue",
widthStyle: "100px",
heightSytyle: "200px",
objStyles:{
border:"5px solid red",
width:"200px",
height:"100px"
}
};
},
methods: {
handle(){
this.heightSytyle == "100px" ? this.heightSytyle = "200px" : this.heightSytyle = "100px" ;
this.objStyles.height == "100px" ? this.objStyles.height = "200px" : this.objStyles.height = "100px" ;
console.log(this.heightSytyle);
}
}
};
</script>
______________________________________________________________________________________________
覆盖用法
<template>
<div>
<div :style="objStyles">第二种写法</div>
<div :style="[objStyles,overrideStyles]">两个写法</div>
</div>
</template>
<script>
export default {
data() {
return {
objStyles:{
border:"5px solid red",
width:"200px",
height:"100px" 有的属性会覆盖 没有的会加上
},
overrideStyles:{
border:"10px solid orange"
}
};
},
methods: {
}
};
</script>
自定义指令
常规
<script>
Vue.directive("focus",{
inserted:function (el) { //钩子函数inserted,bind,update等等 看官方文档
//el表示指令所绑定的元素
el.focus()
}
})
</script>
<input type="text" name="" id="">
<input v-focus type="text" name="" id="">
<input type="text" name="" id="">
带参数
<input v-focus="msg" type="text" name="" id="">
<template>
<div>
<input type="text" name="" id="">
<input v-focus="msg" type="text" name="" id="">
<input type="text" name="" id="">
</div>
</template>
<script>
Vue.directive("focus",{
bind:function (el,binding) {
//el表示指令所绑定的元素
console.log(el,binding)
}
})
export default {
data() {
return {
msg:"hello"
};
},
methods: {
}
};
</script>
打印出来的binding值为
def: {bind: ƒ}
expression: "msg"
modifiers: {}
name: "focus"
rawName: "v-focus"
value: "hello"
__proto__: Object
局部指令
export default {
data() {
return {
msg: "hello"
};
},
methods: {},
directives: {
focus: {
inserted: function(el) {
el.focus();
}
}
}
};
博客详细介绍自定义指令
https://sineava.top/cate/vue/page/vue%E5%85%A5%E9%97%A8.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4
函数简写
在很多时候,你可能想在 bind 和 update 时触发相同行为,而不关心其它的钩子。比如这样写:
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value
})
非简写如下
<input id="search" type="text" class="form-control" v-model="keywords" v-focus v-color="'blue'">
<script>
//自动获取焦点
Vue.directive('focus',{
//在每个函数中,第一个参数永远是el,表示被绑定了指令的那个元素,这个el参数是一个原生js对象
bind:function(){}, //每当指令绑定在元素上的时候,会立即执行这个bind函数,只执行一次
inserted:function(el){
el.focus();
},//元素插入到dom中的时候会执行inserted函数,触发一次
updated:function(){}//当VNode更新的时候,会执行updated,可能会触发多次
});
//写法一:全局
//修改字体颜色
Vue.directive('color',{
bind: function(el,expression) {
el.style.color = binding.value;
console.log(binding.name);//color
console.log(binding.value);//blue
console.log(binding.expression);//'blue'
}
})
//写法二:私有
var vue = new Vue({
el: '##app',
directives: {
'color': {
bind: function(el,binding) {
el.style.color = binding.value;
...
}
}
}
})
</script>
计算属性可以读写 尚硅谷阶段40vue第二节 43分
侦听器
<template>
<div>
<p>姓<input type="text" v-model="firstName"></p>
<p>名<input type="text" v-model="lastName"></p>
需求为写入姓名输出姓名
<p>{{name}}</p>
</div>
</template>
<script>
export default {
data() {
return {
firstName:"",
lastName:"",
name:""
};
},
watch:{
firstName(val){
//val为最新的值
this.name = val + this.lastName;
},
lastName(val){
this.name = this.firstName + val;
}
},
//计算属性也能做到
computed:{
fullName(){
var str = this.firstName + this.lastName;
return str;
}
},
};
</script>
应用场景
<template>
<div>
<p>账号<input type="text" v-model.lazy="name"><span>{{nameMsg}}</span></p>
<p>密码<input type="text" v-model="psw"><span>{{pswMsg}}</span></p>
</div>
</template>
<script>
export default {
data() {
return {
name:"",
psw:"",
nameMsg:"请输入用户名!",
pswMsg:""
};
},
watch:{
name(val){
this.nameMsg = "检查中...";
setTimeout(() => {
if(val){
if(val == "admin"){
this.nameMsg = "可用";
}else{
this.nameMsg = "不可用";
}
}else{
this.nameMsg = "";
}
}, 3000);
}
}
};
</script>
过滤器 格式化数据
常规
可以级联多个 上一个完成的值传给下一个 {{str | upper | lower}}
可以传参数
{{str | upper("abc")}}
Vue.filter("upper",function(val,val2){
console.log(val2); //为abc
})
Vue.filter("upper",function(val){
return val.charAt(0).toUpperCase() + val.slice(1);
})
<template>
<div>
<p>账号<input type="text" v-model="str"></p>
<p>{{str | upper}}</p>
</div>
</template>
<script>
export default {
data() {
return {
str:""
};
},
};
</script>
局部
<template>
<div>
<p>账号<input type="text" v-model="str"></p>
<p>{{str | upper}}</p>
</div>
</template>
<script>
export default {
data() {
return {
str:""
};
},
filters:{
upper(val){
return val.charAt(0).toUpperCase() + val.slice(1);
}
}
};
</script>
组件化开发
传值为 <Test :arr="arr" />
子组件可以直接控制父组件值 直接修改props值就会改变
子组件通过自定义事件向父组件传值
子组件
<button @click='$emit("clicking")'></button>
父组件
<father v-on:clicking="handle"></father>
________________________________________________________________
传值
子组件
<button @click='$emit("clicking",i,num)'></button>
父组件
<father v-on:clicking="handle($event)"></father>
<father v-on:clicking="handle(arguments)"></father> //取过来为数组
组件之间传值(未看)
p a r e n t 和 parent和 parent和children和$refs
在子组件中取父组件的值
console.log(this.$parent.str)
在父组件取子组件的值 为数组
this.$children[0].childrenStr
this.$refs可以直接控制子组件的值 但是不是实时渲染
<div>
<children ref="childrenRef" />
<div/>
methods:{
xxx(){
this.$refs.childrenRef.str = "xxxxxx"
}
}
插槽
常规
父组件
<template>
<div class="home">
<Test :arr="arr" >{{"张三"}}</Test>
</div>
</template>
子组件
<template>
<div>
<p>你好</p>
<slot>默认值</slot>
</div>
</template>
具名插槽新写法v-slot:“name”
父组件
<div class="home">
<Test :arr="arr" >
<span slot="header">头部</span>
{{"张三"}}
<span slot="footer">尾部</span>
</Test>
</div>
子组件
<template>
<div>
<p>头部<slot name="header"></slot></p>
<p>默认<slot></slot></p>
<p>底部<slot name="footer"></slot></p>
</div>
</template>
作用域插槽
子组件
<ul>
<li :key="item.id" v-for="item in arr">
<slot :info="item">默认值</slot>
</li>
</ul>
父组件
<Test :arr="arr">
<template slot-scope="slotProps">
{{slotProps.info.name}}
</template>
</Test>
父组件控制
<Test :arr="arr">
<template slot-scope="slotProps">
<strong v-if="slotProps.info.id==2" class="current">{{slotProps.info.name}}</strong>
<span v-else>{{slotProps.info.name}}</span>
</template>
</Test>
axios
- 支持浏览器和node.js
- 支持promise
- 能拦截请求和响应
- 自动转换json数据
常规写法
axios.get("https://www.baidu.com").then(function(data){
console.log(data);
}).catch(funtion(error){
console.log(error)
})
常用api
get 查询
post 添加
put 修改
delete 删除
get请求参数传递 delete一样
url传参
axios.get("https://www.baidu.com?id=123").then(function(data){
console.log(data);
}).catch(funtion(error){
console.log(error)
})
params传参
axios.get("https://www.baidu.com",{
params:{
id=123
}
})
.then(function(data){
console.log(data);
})
post传参 put一样
默认提交的数据格式为json
axios.post("https://www.baidu.com",{
name:123,
pwd:234
})
.then(function(data){
console.log(data);
})
通过url传参
var params = new URLSearchParams();
params.append("name","123");
params.append("pwd","234");
axios.post("https://www.baidu.com",params).then(function(data){
console.log(data);
})
并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
//两个请求现已完成
}));
响应信息都在data ret里
全局配置 拦截器
全局配置
// 请求的基准地址 下面写的会自动拼接
axios.defaults.baseURL = "https://www.baidu.com/";
// 设置请求头信息
axios.defaults.headers["myHeader"] = "hello";
// 设置超时时间
axios.defaults.timeout = 3000;
请求拦截器request
axios.interceptors.request.use( config => {
console.log(config);
//加个请求头
config.headers.myHeader = "hello";
return config; //最后必须return
}, function (err) {
})
响应拦截器response
axios.interceptors.response.use( res => {
console.log(res);
var data = res.data; //这样以后所有获取到的数据就都是直接的数据 而不是包含很多信息的对象
return data; //最后必须return
}, function (err) {
})
接口调用 async/await用法 es7新语法 更加方便的异步
await可以得到异步的结果
async function queryData() {
var ret = await axios.get("../");
console.log(ret.data);
}
queryData();
// 如果return的话还可以通过then
async function queryData() {
var ret = await axios.get("../");
//console.log(ret.data);
return ret.data;
}
queryData().then(function (data) {
console.log(data);
}).catch(function(error){
console.log(error)
})
这是项目中的实例
var that = this;
async function queryData() { 这里是链接 这里是发送的账号密码
var ret = await that.$axios.post("login", that.loginForm);
return ret.data;
}
queryData()
.then( data => {
console.log(data);
}).catch( error => {
console.log(error)
})
这是项目中的实例2
methods: {
//获取所有左侧子菜单
async getMenuList() {
const { data: res } = await this.$axios.get("menus");
}
},
created() {
this.getMenuList();
}
async/await处理多个异步任务
async function queryData() {
var info = await axios.get("../"); //用await顺序写
var ret = await axios.get("../?info=" + info.data)
return ret.data;
}
queryData().then(function (data) {
console.log(data);
})
前端路由 this.$route.path
简易前端路由 没有用router
<template>
<div>
<a href="#/r1">路由1</a>
<a href="#/r2">路由2</a>
<a href="#/r3">路由3</a>
<p>
<component :is="comName"></component>
</p>
</div>
</template>
<script>
import r1 from "./router-Test/router1";
import r2 from "./router-Test/router2";
import r3 from "./router-Test/router3";
export default {
data() {
return {
comName:"r1"
};
},
components:{
r1,
r2,
r3
}
};
window.onhashchange = function () {
console.log(location);
// 通过location.hash 获取到最新的hash值
this.comName = location.hash.slice(2); //这里组件化开发拿不到vm
//this为window
}
</script>
简单vue-router
- 引入库文件
- 添加路由链接
<router-link to="/user"></router-link>
vue提供的标签,默认被渲染为a标签,to为href属性,to值默认会渲染为#开头的hash地址
- 路由填充位
<router-view></router-view>
- 定义路由组件
- 配置路由规则并创建路由实例
- 把路由挂载到Vue根实例中
<template>
<div>
<router-link to="/r1">路由1</router-link>
<router-link to="/r2">路由2</router-link>
<router-link to="/r3">路由3</router-link>
<p>
<router-view></router-view>
</p>
</div>
</template>
<script>
import R1 from "./router-Test/router1";
import R2 from "./router-Test/router2";
import R3 from "./router-Test/router3";
import Vue from 'vue';
import VueRouter from "vue-router";
//注册插件
Vue.use(VueRouter);
//路由实例
var router = new VueRouter({
//路由规则数组
routes:[ //path为hash地址,component为展示组件不接受字符串
{path:"/r1",component:R1},
{path:"/r2",component:R2},
{path:"/r3",component:R3},
]
})
export default {
data() {
return {
};
},
router //挂载
};
</script>
重定向
{path:"/" , redirect:"/user"}
嵌套路由
父路由
<template>
<div>
<router-link to="/r1">路由1</router-link>
<router-link to="/r2">路由2</router-link>
<router-link to="/r3">路由3</router-link>
<p>
<router-view></router-view>
</p>
</div>
</template>
<script>
import R1 from "./router-Test/router1";
import R2 from "./router-Test/router2";
import R3 from "./router-Test/router3";
import Vue from 'vue';
import VueRouter from "vue-router";
import router2Son1 from "./router-Test/router2Son/router2Son1";
import router2Son2 from "./router-Test/router2Son/router2Son2";
//注册插件
Vue.use(VueRouter);
//路由实例
var router = new VueRouter({
//路由规则数组
routes:[ //path为hash地址,component为展示组件不接受字符串
{path:"/" , redirect:"r1"},
{path:"/r1",component:R1},
{path:"/r2",component:R2,children:[
{path:"/r2/tab1",component:router2Son1},
{path:"/r2/tab2",component:router2Son2},
]},
{path:"/r3",component:R3},
]
})
export default {
data() {
return {
};
},
router //挂载
};
</script>
子组件,提前准备好子子组件
<template>
<div>
<p>路由2</p>
<router-link to="/r2/tab1">tab1</router-link>
<router-link to="/r2/tab2">tab2</router-link>
<!-- 子路由占位符 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
动态路由匹配 传参 与对应路由形成高度耦合
父路由
<template>
<div>
<router-link to="/r1">路由1</router-link>
<router-link to="/r2/1">路由2/1</router-link>
<router-link to="/r2/2">路由2/2</router-link>
<router-link to="/r2/3">路由2/3</router-link>
<router-link to="/r3">路由3</router-link>
<p>
<router-view></router-view>
</p>
</div>
</template>
<script>
import R1 from "./router-Test/router1";
import R2 from "./router-Test/router2";
import R3 from "./router-Test/router3";
import Vue from "vue";
import VueRouter from "vue-router";
//注册插件
Vue.use(VueRouter);
//路由实例
var router = new VueRouter({
//路由规则数组
routes: [
//path为hash地址,component为展示组件不接受字符串
{ path: "/", redirect: "r1" },
{ path: "/r1", component: R1 },
{ path: "/r2/:uid", component: R2 },
{ path: "/r3", component: R3 }
]
});
export default {
data() {
return {};
},
router //挂载
};
</script>
子路由 通过$route而不是ter
<template>
<div>
<p>路由2ID为{{$route.params.uid}}</p>
<router-link to="/r2/tab1">tab1</router-link>
<router-link to="/r2/tab2">tab2</router-link>
<!-- 子路由占位符 -->
<router-view></router-view>
</div>
</template>
路由组件传递参数
var router = new VueRouter({
{ path: "/r1", component: R1 , props : true },
})
父路由
<template>
<div>
<router-link to="/r1">路由1</router-link>
<router-link to="/r2/1">路由2/1</router-link>
<router-link to="/r2/2">路由2/2</router-link>
<router-link to="/r2/3">路由2/3</router-link>
<router-link to="/r3">路由3</router-link>
<p>
<router-view></router-view>
</p>
</div>
</template>
<script>
import R1 from "./router-Test/router1";
import R2 from "./router-Test/router2";
import R3 from "./router-Test/router3";
import Vue from "vue";
import VueRouter from "vue-router";
//注册插件
Vue.use(VueRouter);
//路由实例
var router = new VueRouter({
//路由规则数组
routes: [
//path为hash地址,component为展示组件不接受字符串
{ path: "/", redirect: "r1" },
{ path: "/r1", component: R1 },
{ path: "/r2/:uid", component: R2 , props:true},
{ path: "/r3", component: R3 }
]
});
export default {
data() {
return {};
},
router //挂载
};
</script>
子路由
<template>
<div>
<p>路由2ID为{{$route.params.uid}}</p>
<p>id为{{uid}}</p> 这里就是拿到的值
<router-link to="/r2/tab1">tab1</router-link>
<router-link to="/r2/tab2">tab2</router-link>
<!-- 子路由占位符 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
props:["uid"]
}
</script>
如果写为对象形式则变为正常传参,之前:uid作废
如果函数形式则都可以传
<script>
var router = new VueRouter({
//路由规则数组
routes: [
//path为hash地址,component为展示组件不接受字符串
{ path: "/", redirect: "r1" },
{ path: "/r1", component: R1 },
{ path: "/r2/:uid", component: R2 , props : { name: 123 , pwd:234 }},
{ path: "/r3", component: R3 }
]
});
</script>
_________________________________________________________
<template>
<div>
<p>路由2ID为{{$route.params.uid}}</p>
<p>namepwd为{{name + "" + pwd}}</p>
<router-link to="/r2/tab1">tab1</router-link>
<router-link to="/r2/tab2">tab2</router-link>
<!-- 子路由占位符 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
props:["name","pwd"]
}
</script>
——————————————————————函数形式——————————————————
<script>
var router = new VueRouter({
//路由规则数组
routes: [
//path为hash地址,component为展示组件不接受字符串
{ path: "/", redirect: "r1" },
{ path: "/r1", component: R1 },
{ path: "/r2/:uid", component: R2 , props : route => ({name: 123, pwd:234,uid:route.params.uid}) },
{ path: "/r3", component: R3 }
]
});
</script>
<template>
<div>
<p>路由2ID为{{$route.params.uid}}</p>
<p>{{uid}}</p>
<p>{{name}}</p>
<p>{{pwd}}</p>
<router-link to="/r2/tab1">tab1</router-link>
<router-link to="/r2/tab2">tab2</router-link>
<!-- 子路由占位符 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
props:["uid","name","pwd"]
}
</script>
<style>
命名路由 name
<template>
<div>
<router-link to="/r1">路由1</router-link>
<router-link to="/r2/1">路由2/1</router-link>
<router-link :to="{name:'rtwo' , params :{uid : 2} }">路由2/2</router-link>
<router-link to="/r2/3">路由2/3</router-link>
<router-link to="/r3">路由3</router-link>
<p>
<router-view></router-view>
</p>
</div>
</template>
<script>
import R1 from "./router-Test/router1";
import R2 from "./router-Test/router2";
import R3 from "./router-Test/router3";
import Vue from "vue";
import VueRouter from "vue-router";
//注册插件
Vue.use(VueRouter);
//路由实例
var router = new VueRouter({
//路由规则数组
routes: [
//path为hash地址,component为展示组件不接受字符串
{ path: "/", redirect: "r1" },
{ path: "/r1", component: R1 },
{ name:"rtwo" , path: "/r2/:uid", component: R2 , props : route => ({name: 123, pwd:234,uid:route.params.uid}) },
{ path: "/r3", component: R3 }
]
});
export default {
data() {
return {};
},
router //挂载
};
</script>
编程式导航(之前为声明式导航)
this.$router.push("hash地址") //转跳
this.$router.go(1) //1或者-1 前进后退
this.$router.push("home");
this.$router.push({ path: "/home" });
//传递参数
this.$router.push({ name: "home" , params:{ uid:123 } });
//带查询参数 会被拼接到地址的后面
this.$router.push({ path:"/home" , query : { name: "list" } });
/home?name=list
this.$router.replace//替换最后一个历史记录(当前)
$route 当前路由信息
$router 操作路由
路由守卫 监视路由 导航守卫
不能为replace 因为不会留历史记录
用watch不推荐简单,只能看不能操作干预
watch:{
$route(value , old_value){
console.log(value,old_value)
}
}
路由守卫 导航守卫 能看也能控制
比如填写表单 注册页你要跳走这页可就没了 问你是否跳走 否则需要阻止路由跳转
let router = new VueRouter({
routers:[
{
path:"/news",
name:"news",
component:{
News,
//to将要访问的,from从那个路由来的,next()放行函数
beforeRouteUpdate(to , from , next){
if( true==confirm('确定离开?') ){
next();
}
}
}
}
]
})
//项目实例
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/Login'
import Home from '../components/Home'
Vue.use(VueRouter)
const routes = [
{ path: '/', redirect: './login' },
{ path: '/login', component: Login },
{ path: '/home', component: Home },
]
const router = new VueRouter({
routes
})
//在暴露之前挂载路由守卫
router.beforeEach((to, from, next) => {
if(to.path == '/login'){
return next()
}
//获取token
const token = window.sessionStorage.getItem('token')
if(!token){
return next('/login')
}
next();
})
export default router
多视图 命名视图
<router-view name="header"></router-view>
<router-view></router-view>
<router-view name="footer"></router-view>
components加s
let router = new VueRouter({
routers:[
{
path:"/",
name:"index",
components:{
default:indexCmp,
header:headerCmp,
footer:footerCmp
}
},
{
path:"/news",
name:"news",
components:{
default:newsCmp, //default为默认 上面视图可以给一个默认的 也可以都给起名字
header:headerCmp,
footer:footerCmp2
}
}
]
})