Vue.js -- 指令 第一部分
Vue.js
1. 指令
表达式的值除了可以出现内容中,也可以使用在其它位置,比如:属性。但是不能使用 {{}}
语法,而是需要 指令
v-指令名称 =
表达式
(加“ ”,但不是普通字符串)
v- 前缀代表vue ~ ~ ~
在 vue
中,指令是一个带有 v-
前缀的属性,与普通属性不一样的地方在于,指令的值是引号括起来的 表达式
,不同的指令有不同的作用,vue
内置了一些常用的指令,后期我们还可以自定义属于自己的指令
- 内容输出
- 循环
- 逻辑
- 属性绑定
- 事件
- 其它
2. 内容输出
通过 {{}}
我们可以很方便的从模板中输出数据,但是这种方式会有一个问题,当页面加载渲染比较慢的时候,页面中会出现 {{}}
,vue
提供了几个指令来解决这个问题
指令中 的 表达式 不需要使用
{{}}
2.1 v-text
v-text
:更新元素的文本内容textContent。
<p v-text="title"></p>
<!-- 和下面的一样 -->
<p>{{title}}</p>
<!-- {{}}与v-text区别示例 {{}}可以更新部分内容 -->
<h1>hello,{{title}}</h1>
<!-- v-text会填充整个innerHTML -->
<h1 v-text="title"></h1>
v-text 与 {{}} 区别:
v-text
会填充整个innerHTML
,也是一个弊端- 如果要更新部分的 textContent,需要使用
{{ }}
插值。
2.2 v-cloak
v-cloak
:保持在元素上 直到 关联实例结束编译。
- 不需要表达式
- 这个指令 保持在元素上 直到 关联实例结束编译。
- 和 CSS 规则 如
[v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的 {{ }} (Mustache 标签) 直到实例准备完毕。
白话理解:编译结束时,[v-cloak] 指令失效,
在示例准备完毕结束 之前 实施[v-cloak] 的指令,这里的例子也就是隐藏元素,编译结束后,则不再实行[v-cloak] 的指令
需要配合 css 进行处理
<style> [v-cloak] { display: none; } </style>
<p v-cloak>{{title}}</p>
2.3 v-html
v-html
:更新元素的 innerHTML,可以让内容作为 html 进行解析
注意:内容按
普通 HTML
插入 - 不会作为 Vue 模板进行编译。
如果试图使用v-html
组合模板,可以重新考虑是否通过使用组件来替代。
为了防止xss
攻击,默认情况下输出是不会作为html
解析的,通过v-html
可以让内容作为html
进行解析
<div id="app">
<!-- 内容按普通 HTML插入 不会作为html来解析的 输出的是文本-->
<p>{{content}}</p>
<!-- 使用v-html 可作为html来解析的 -->
<p v-html="content" ></p>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
content:"<style> body{background:pink} </style>",
}
});
</script>
页面输出对比:
2.4 v-once
v-once
:只渲染元素和组件一次,后期的更新不再渲染
<div id="app">
<div v-once>
<p>{{msg}}</p>
</div>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
msg:"我是1"
}
});
</script>
2.5 v-pre
v-pre
:忽略这个元素和它子元素内容的编译
<div id="app">
<span v-pre>{{msg}}</span>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
msg:"我是1"
}
});
</script>
页面显示:
3. 逻辑处理
3.1 v-show
v-show
:根据表达式的值(布尔值),切换元素的显示与隐藏(display 属性)
改变的只有 该元素的display样式
适用于 状态切换比较频繁 的情况(例如table选项卡、轮播图……)
<div id="app"> <div v-show="islogin">这是隐私</div> </div> <script> let app = new Vue({ el:"#app", data:{ islogin:true } }) </script>
当
islogin:true
时的页面:
当islogin:false
时的页面:
3.2 v-if
v-if
:根据表达式的值(布尔值),创建或销毁元素
改变的是元素的结构(渲染或者删除)
适用于 状态切换 不频繁 的情况 (例如删除购物车……)
v-if与 v-show 的区别:
v-show
:改变的只有 该元素的display样式
适用于:状态切换 比较 频繁 的情况(例如table选项卡、轮播图……)
v-if
: 改变的是元素的结构(渲染或者删除)
适用于:状态切换 不频繁 的情况(例如删除购物车……)
<div id="app"> <div v-show="islogin">这是隐私</div> <br> <div v-if="islogin">欢迎</div> </div> <script> let app = new Vue({ el:"#app", data:{ islogin:true } }) </script>
当
islogin:true
时的页面:
当islogin:false
时的页面:
3.3 v-else / v-else-if
- 限制:
前一兄弟元素必须有 v-if 或 v-else-if。
v-if 和 v-else以及 v-else-if 之间 必须是连接的,中间不能出现其他元素,否则会报错 - 用法:为 v-if 或者 v-else-if 添加“else 块”。
<div id="app"> <div v-show="islogin">这是隐私</div> <br> <div v-if="islogin">欢迎</div> <!-- <p>哈哈哈</p> --> <div v-else="islogin">请登录</div> </div> <script> let app = new Vue({ el:"#app", data:{ islogin:true } }) </script>
当
islogin:true
时的页面:
当islogin:false
时的页面:
4. 循环与列表
4.1 v-for
根据数据循环渲染 v-for
指令所在的元素及其子元素
可以循环的数据:Array | Object | number | string | Iterable (2.6 新增)
<div v-for="(item, index) in items"></div>
<div v-for="(val, key) in object"></div>
<div v-for="(val, key, index) in object"></div>
<!-- index 属性名对应的下标 -->
循环数组,循环对象实例:
<!-- 指令中的循环 -->
<div id="app">
<ul>
<!-- of in 在这里使用没有区别 -->
<!-- 1. 循环数组中的 -->
<li v-for = "user in users" :key="user.id">
<!-- 没加 :key="user.id" 的时候 input框里选中的不跟数据变化走-->
<input type="checkbox">
{{user.id}} - {{user.name}}
</li>
</ul>
<!-- 2. 循环对象中的 -->
<div v-for="(val,name,index) in Object">
<span>索引值:{{index}}</span>
<span>属性名:{{name}},值:{{val}}</span>
</div>
</div>
v-for 中也可以使用 of 语法,在 vue 中两者没有什么区别
4.2 :key
默认情况下,在渲染 DOM
过程中使用 原地复用 ,这样一般情况下会比较高效,但是对于循环列表,特别是依赖某种状态的列表,会有一些问题,我们可以通过 :key
属性,来给每个循环节点添加一个标识
v-for和:key代码示例
<!-- 指令中的循环 --> <div id="app"> <ul> <!-- of in 在这里使用没有区别 --> <!-- 1. 循环数组中的 --> <li v-for = "user in users" :key="user.id"> <!-- 没加 :key="user.id" 的时候 input框里选中的不跟数据变化走--> <input type="checkbox"> {{user.id}} - {{user.name}} </li> </ul> <!-- 2. 循环对象中的 --> <div v-for="(val,name,index) in Object"> <span>索引值:{{index}}</span> <span>属性名:{{name}},值:{{val}}</span> </div> <!-- <div v-for="(item, index) in items"></div> <div v-for="(val, key) in object"></div> <div v-for="(val, key, index) in object"></div> --> <!-- index 属性名对应的下标 --> </div> <script> // 虚拟dom vdom 有一个机制:每次加载过后,会像缓存似的留一个备份, // 等下一次渲染的时候,去看跟之前留的有什么不一样的地方 // 有变动的地方就改一下,没有变大的就原样渲染到html上 // 也为了尽可能少的去修改dom,为了达到优化加载速度的目的 //所以执行数据排序sort()时,仅是id,name改变了,四个input里不变,所以选中框选中情况没有重新渲染,因为跟备份的是一致的, //想要跟随去动,使用 :key 给每个循环节点添加一个标识 //例如 :key="user.id" //模板 => vdom =>html // 留一备份 { li : "1" li : "2" li : "3" li : "4" } let app = new Vue({ el:"#app", data:{ users:[ {id:1,name:"小马"}, {id:2,name:"小陈"}, {id:3,name:"小冯"}, {id:4,name:"小金"} ], Object:{ x:"a", y:"b", z:"c" } } }); app.users.sort((a,b)=>{ return Math.random() - .5 }); </script>
随机排序前:
随机排序后:
5. 属性绑定
5.1 v-bind
绑定数据(表达式)到指定的属性上,<div v-bind:参数="值/表达式"></div>
,这里的参数就是指定的属性名称
v-指令名称:参数=“指令的值” (参数是指定的属性名称)
注意跟不加v-bind:
或者:
作区分,不加的话则是原生获取属性的方式
<div id="app">
<div v-bind:id="myId"></div>
<div v-bind:class="myclass"></div>
<div :id="Id"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
myclass:"box",
Id:"haha",
myId: 'kaikeba'
}
})
</script>
缩写
有的一些常用指令会有对应的缩写,v-bind
对应的缩写为::
<div :id="myId"></div>
5.2 样式
针对样式属性,v-bind
值有一些特殊的写法
5.2.1 style
- 原生普通写法
<div style="width: 100px; height: 100px; background: red"></div>
- v-bind 写法
<div :style="'width: 100px; height: 100px; background: red'"></div>
- 对象写法
<div :style="style1"></div>
...
<script>
new Vue({
el: '#app',
data: {
style1: {
width: '100px',
height: '100px',
background: 'green'
}
}
});
</script>
- 数组写法:有重复的优先显示最后一个;数组
[]
内不能写引号
<div :style="[style1, style2]"></div>
...
<script>
new Vue({
el: '#app',
data: {
style1: {
width: '100px',
height: '100px',
background: 'green'
},
style2: {
border: '1px solid black'
}
}
});
</script>
5.2.2 class
- 原生普通写法
<div class="box1 box2"></div>
- v-bind 写法
<div :class="'box1 box2'"></div>
- 数组写法
<div :class="['box1', 'box2']"></div>
- 对象写法 (布尔值)
<div :class="{'box1': isActive, 'box2': isChecked}"></div>
使用对象写法,可以根据值(boolean)动态添加对应的 class
true的时候显示样式,false不显示,都是true的时候,就根据css样式优先级来显示
<style>
div{
font-size: 13px;
text-align: center;
line-height: 50px;
}
.box1{
width: 200px;
height: 200px;
background:pink
}
.box2{
width: 300px;
height: 100px;
background:yellow;
border: 2px solid black;
}
</style>
</head>
<body>
<div id="app">
<!-- 原生写法 -->
<div style="width : 100px; height : 100px; background-color: yellowgreen;">原生style</div>
<!-- v-bind -->
<div :style="style1">:style="style1"</div>
<!-- 数组写法
:style 获取的是具体的样式
:class 获取的是类名
-->
<div :class="box">:class="box"</div>
<div :style="[style1,style2]">:style="[style1,style2]"</div>
<!-- 对象写法 -->
<div :class="{'box1':new_box,'box2':two_box}">:class="{'box1':new_box,'box2':two_box}"</div>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
style1:{
width:'100px',
height:'100px',
background:'blue'
},
style2:{
width:'150px',
height:'150px',
background:'green',
border:'2px solid black'
},
box:"school",
new_box:true,
two_box:false
}
})
</script>
class对象写法中
new_box:true, two_box:false 时
new_box:true, two_box:true 时
6. 数据流
6.1 单向数据流
通过上面的知识点和案例,我们可以看到,当数据更新的时候,页面视图就会更新,但是页面视图中绑定的元素更新的时候,对应的数据是不会更新的
我们称为:单向数据流 数据 => 视图
- v-bind: 单向数据绑定。 数据 => 视图
<input type="text" :value="msg2" />
<div>{{msg2}}</div>
在 vue 中,还有一种双向数据流绑定的方式
6.2 双向数据流 v-model
<input type="text" v-model="msg" />
<div>{{msg}}</div>
数据
msg
更新,视图中input
的value
就会更新。同时,当 input 中的value
更新的时候,数据msg
也会更新,这就是我们说的 数据双向绑定 [与 React 中的受控组件类似]
v-model: 双向数据绑定:数据=>视图 ,视图=>数据 用于交互性元素
不是所有的标签(组件)都支持 v-model
– 默认:交互元素(input, textarea, select)
不是所有的属性都支持 v-model
– v-model 只能绑定一个指定好的属性
input : value
textarrea : value
select : selected
非交互: div p img 等静态类标签(不需要统计信息的)
<div id="app">
<!-- 双向数据绑定 数据=>视图 ,视图=>数据 -->
<input type="text" v-model="msg"> 双向
<div>{{msg}}</div>
<br><hr><br>
<!-- 单向绑定 数据=>视图 -->
<input type="text" :value="msg2"> 单向
<div>{{msg2}}</div>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
msg:"123",
msg2:"abc"
}
})
</script>
页面显示:
数据=>视图(单向、双向都可以):
视图=>数据 (只有双向才可以):