v-cloak:
使用 v-cloak 能够解决 插值表达式闪烁的问题,不使用v-cloak的话,在用户网速不理想的时候,页面加载时会先直接显示{{message}},然后再显示数据。
<div>
{{ message }}
</div>
因为这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如[v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。即在实例结束编译前,元素会按照下面的样式进行元素的显示,结束编译后这个样式就不会起作用了。
[v-cloak] {
display: none;
}
<div v-cloak>
{{ message }}
</div>
v-text:
默认 v-text 是没有闪烁问题的。
<span v-text="msg"></span>
<!-- 和下面的一样 -->
<span>{{msg}}</span>
v-cloak和v-text之间的区别:
v-text会覆盖元素中原本的内容,但是 插值表达式 只会替换自己的这个占位符,不会把 整个元素的内容清空
<p v-cloak>++++++++ {{ msg }} ----------</p>
<h4 v-text="msg">==================</h4>
v-html和v-text的区别:
<div v-text="msg2">1212112</div>
<div v-html="msg2">1212112</div>
v-bind:
是 Vue中,提供的用于绑定属性的指令
<input type="button" value="按钮" v-bind:title="mytitle + '123'">
注意: v-bind: 指令可以被简写为 :要绑定的属性
v-bind 中,可以写合法的JS表达式
v-on:
事件绑定机制
<input type="button" value="按钮" :title="mytitle + '123'" v-on:click="show">
注意: v-on: 指令可以被简写为 @要绑定的事件,在Vue中,使用事件绑定机制,为元素指定处理函数的时候,如果加了小括号,就可以给函数传参了
事件修饰符:
.stop 阻止冒泡
.prevent 阻止默认事件
.capture 添加事件侦听器时使用事件捕获模式
.self 只当事件在该元素本身(比如不是子元素)触发时触发回调,通过捕获冒泡触发的都不执行事件回调
.once 事件只触发一次
<!-- 点击链接后不会跳转到百度的页面 -->
<a href="http://www.baidu.com" @click.prevent.once="linkClick">有问题,先去百度</a>
.stop 和 .self 的区别:
<div class="outer" @click="div2Handler">
<div class="inner" @click="div1Handler">
<input type="button" value="戳他" @click.stop="btnHandler">
</div>
</div>
<!-- .self 只会阻止自己身上冒泡行为的触发,并不会真正阻止 冒泡的行为 -->
<div class="outer" @click="div2Handler">
<div class="inner" @click.self="div1Handler">
<input type="button" value="戳他" @click="btnHandler">
</div>
</div>
v-model和双向数据绑定:
v-model是唯一可以实现双向数据绑定的指令。双向数据绑定:M层数据改变后V层对应的数据会修改,V层数据改变后M层对应的数据也会修改。
v-model和v-bind的区别:
v-bind 只能实现数据的单向绑定,从 M 自动绑定到 V, 无法实现数据的双向绑定:
<h4>{{ msg }}</h4>
<!-- v-bind 只能实现数据的单向绑定,从 M 自动绑定到 V, 无法实现数据的双向绑定 -->
<input type="text" v-bind:value="msg" style="width:100%;">
使用 v-model 指令,可以实现 表单元素和 Model 中数据的双向数据绑定
注意: v-model 只能运用在 表单元素中
<h4>{{ msg }}</h4>
<input type="text" style="width:100%;" v-model="msg">
class与style的绑定:
使用class样式:
数组
<h1 :class="['red', 'thin']">这是一个邪恶的H1</h1>
数组中使用三元表达式
<h1 :class="['red', 'thin', isactive?'active':'']">这是一个邪恶的H1</h1>
数组中嵌套对象
<h1 :class="['red', 'thin', {'active': isactive}]">这是一个邪恶的H1</h1>
直接使用对象
<h1 :class="{red:true, italic:true, active:true, thin:true}">这是一个邪恶的H1</h1>
.red {
color: red;
}
.thin {
font-weight: 200;
}
.italic {
font-style: italic;
}
.active {
letter-spacing: 0.5em;
}
<div id="app">
<h1 class="red thin">这是一个很大很大的H1,大到你无法想象!!!</h1>
<!-- 第一种使用方式,直接传递一个数组,注意: 这里的 class 需要使用 v-bind 做数据绑定 -->
<h1 :class="['thin', 'italic']">这是一个很大很大的H1,大到你无法想象!!!</h1>
<!-- 在数组中使用三元表达式 -->
<h1 :class="['thin', 'italic', flag?'active':'']">这是一个很大很大的H1,大到你无法想象!!!</h1>
<!-- 在数组中使用 对象来代替三元表达式,提高代码的可读性 -->
<h1 :class="['thin', 'italic', {'active':flag} ]">这是一个很大很大的H1,大到你无法想象!!!</h1>
<!-- 在为 class 使用 v-bind 绑定 对象的时候,对象的属性是类名,由于 对象的属性可带引号,也可不带引号,所以 这里我没写引号; 属性的值 是一个标识符 -->
<h1 :class="classObj">这是一个很大很大的H1,大到你无法想象!!!</h1>
</div>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
flag: true,
classObj: { red: true, thin: true, italic: false, active: false }
},
methods: {}
});
使用内联样式:
直接在元素上通过 `:style` 的形式,书写样式对象
<h1 :style="{color: 'red', 'font-size': '40px'}">这是一个善良的H1</h1>
将样式对象,定义到 `data` 中,并直接引用到 `:style` 中
在data上定义样式:
data: {
h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' }
}
在元素中,通过属性绑定的形式,将样式对象应用到元素中:
<h1 :style="h1StyleObj">这是一个善良的H1</h1>
在 `:style` 中通过数组,引用多个 `data` 上的样式对象
在data上定义样式:
data: {
h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' },
h1StyleObj2: { fontStyle: 'italic' }
}
在元素中,通过属性绑定的形式,将样式对象应用到元素中:
<h1 :style="[h1StyleObj, h1StyleObj2]">这是一个善良的H1</h1>
v-for:
v-for循环普通数组:
<div id="app">
<p v-for="(item, i) in list">索引值:{{i}} --- 每一项:{{item}}</p>
</div>
var vm = new Vue({
el: '#app',
data: {
list: [1, 2, 3, 4, 5, 6]
},
methods: {}
});
v-for循环对象数组:
<div id="app">
<p v-for="(user, i) in list">Id:{{ user.id }} --- 名字:{{ user.name }} --- 索引:{{i}}</p>
</div>
var vm = new Vue({
el: '#app',
data: {
list: [
{ id: 1, name: 'zs1' },
{ id: 2, name: 'zs2' },
{ id: 3, name: 'zs3' },
{ id: 4, name: 'zs4' }
]
},
methods: {}
});
v-for循环对象:
<div id="app">
<!-- 注意:在遍历对象身上的键值对的时候, 除了 有 val key ,在第三个位置还有 一个 索引 -->
<p v-for="(val, key, i) in user">值是: {{ val }} --- 键是: {{key}} -- 索引: {{i}}</p>
</div>
var vm = new Vue({
el: '#app',
data: {
user: {
id: 1,
name: 'aha',
gender: '女'
}
},
methods: {}
});
迭代数字
<div id="app">
<!-- in 后面我们放过 普通数组,对象数组,对象, 还可以放数字 -->
<!-- 注意:如果使用 v-for 迭代数字的话,前面的 count 值从 1 开始 -->
<p v-for="count in 10">这是第 {{ count }} 次循环</p>
</div>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {}
});
key:
当 Vue.js 用 v-for
正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个类似 Vue 1.x 的 track-by="$index"
在一些特殊情况中,不使用key时会出现的问题
<div id="app">
<div>
<label>Id:
<input type="text" v-model="id">
</label>
<label>Name:
<input type="text" v-model="name">
</label>
<input type="button" value="添加" @click="add">
</div>
<p v-for="item in list" >
<input type="checkbox">{{item.id}} --- {{item.name}}
</p>
</div>
var vm = new Vue({
el: '#app',
data: {
id: '',
name: '',
list: [
{ id: 1, name: '李斯' },
{ id: 2, name: '嬴政' },
{ id: 3, name: '赵高' },
{ id: 4, name: '韩非' },
{ id: 5, name: '荀子' }
]
},
methods: {
add() { // 添加方法
this.list.unshift({ id: this.id, name: this.name })
}
}
});
出现的问题,本来是第四项被check,但是在头部添加一项以后,被check的变为了第三项
使用key以后:
2.2.0+ 的版本里,**当在组件中使用** v-for 时,key 现在是必须的。
<!-- 注意: v-for 循环的时候,key 属性只能使用 number或者string -->
<!-- 注意: key 在使用的时候,必须使用 v-bind 属性绑定的形式,指定 key 的值 -->
<!-- 在组件中,使用v-for循环的时候,或者在一些特殊情况中,如果 v-for 有问题,必须 在使用 v-for 的同时,指定 唯一的 字符串/数字 类型 :key 值 -->
<p v-for="item in list" :key="item.id">
<input type="checkbox">{{item.id}} --- {{item.name}}
</p>
添加一项元素以后,依然是第四项被check
v-if和v-show:
v-if 的特点:每次都会重新删除或创建元素
v-show 的特点: 每次不会重新进行DOM的删除和创建操作,只是切换了元素的 display:none 样式
v-if 有较高的切换性能消耗
v-show 有较高的初始渲染消耗(因为即使元素不被显示,也会被创建,只是加了个display:none样式) -->
如果元素涉及到频繁的切换,最好不要使用 v-if, 而是推荐使用 v-show
如果元素可能永远也不会被显示出来被用户看到,则推荐使用 v-if
<div id="app">
<input type="button" value="toggle" @click="flag=!flag">
<h3 v-if="flag">这是用v-if控制的元素</h3>
<h3 v-show="flag">这是用v-show控制的元素</h3>
</div>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
flag: false
},
methods: {
toggle() {
this.flag = !this.flag
}
}
});
过滤器:
Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化。过滤器可以用在两个地方:mustache 插值和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符指示;过滤器可以串联,会将filterA
的结果传递到 filterB
中
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
全局过滤器(所有VM实例都能共享这个过滤器):
<p>{{ msg | msgFormat('疯狂+1', '123') | test }}</p>
// 定义一个 Vue 全局的过滤器,名字叫做 msgFormat
Vue.filter('msgFormat', function (msg, arg, arg2) {
// 字符串的 replace 方法,第一个参数,除了可写一个 字符串之外,还可以定义一个正则
return msg.replace(/单纯/g, arg + arg2)
})
Vue.filter('test', function (msg) {
return msg + '========'
})
私有过滤器:
<td>{{ item.ctime | dateFormat() }}</td>
filters: { // 定义私有过滤器 过滤器有两个 条件 【过滤器名称 和 处理函数】
// 过滤器调用的时候,采用的是就近原则,如果私有过滤器和全局过滤器名称一致了,这时候 优先调用私有过滤器
dateFormat: function (dateStr, pattern = '') {
// 根据给定的时间字符串,得到特定的时间
var dt = new Date(dateStr)
// yyyy-mm-dd
var y = dt.getFullYear()
var m = (dt.getMonth() + 1).toString().padStart(2, '0')
var d = dt.getDate().toString().padStart(2, '0')
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`
} else {
// padStart填充字符串
var hh = dt.getHours().toString().padStart(2, '0')
var mm = dt.getMinutes().toString().padStart(2, '0')
var ss = dt.getSeconds().toString().padStart(2, '0')
return `${y}-${m}-${d} ${hh}:${mm}:${ss} ~~~~~~~`
}
}
}
自定义全局按键修饰符:
<input type="text" class="form-control" v-model="name" @keyup.f2="add">
Vue.config.keyCodes.f2 = 113
相当于:
<input type="text" class="form-control" v-model="name" @keyup.113="add">
自定义指令:
定义全局的指令:
// 使用 Vue.directive() 定义全局的指令 v-focus
// 其中:参数1 : 指令的名称,注意,在定义的时候,指令的名称前面,不需要加 v- 前缀,
// 但是: 在调用的时候,必须 在指令名称前 加上 v- 前缀来进行调用
// 参数2: 是一个对象,这个对象身上,有一些指令相关的函数,这些函数可以在特定的阶段,执行相关的操作
Vue.directive('focus', {
bind: function (el) { // 每当指令绑定到元素上的时候,会立即执行这个 bind 函数,只执行一次
// 注意: 在每个 函数中,第一个参数,永远是 el ,表示 被绑定了指令的那个元素,这个 el 参数,是一个原生的JS对象
// 在元素 刚绑定了指令的时候,还没有 插入到 DOM中去,这时候,调用 focus 方法没有作用
// 因为,一个元素,只有插入DOM之后,才能获取焦点
// el.focus()
},
inserted: function (el) { // inserted 表示元素 插入到DOM中的时候,会执行 inserted 函数【触发1次】
el.focus()
// 和JS行为有关的操作,最好在 inserted 中去执行,放置 JS行为不生效
},
updated: function (el) { // 当VNode更新的时候,会执行 updated, 可能会触发多次
}
})
// 自定义一个 设置字体颜色的 指令
Vue.directive('color', {
// 样式,只要通过指令绑定给了元素,不管这个元素有没有被插入到页面中去,这个元素肯定有了一个内联的样式
// 将来元素肯定会显示到页面中,这时候,浏览器的渲染引擎必然会解析样式,应用给这个元素
bind: function (el, binding) {
// el.style.color = 'red'
// console.log(binding.name)
// 和样式相关的操作,一般都可以在 bind 执行
// console.log(binding.value)
// console.log(binding.expression)
el.style.color = binding.value
}
})
自定义私有指令:
directives: { // 自定义私有指令
'fontweight': { // 设置字体粗细的
bind: function (el, binding) {
el.style.fontWeight = binding.value
}
},
'fontsize': function (el, binding) { // 注意:这个 function 等同于 把 代码写到了 bind 和 update 中去
el.style.fontSize = parseInt(binding.value) + 'px'
}
}
v-for 的列表过渡
1. 定义过渡样式:
<style>
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateY(10px);
}
.list-enter-active,
.list-leave-active {
transition: all 0.3s ease;
}
</style>
2. 定义DOM结构,其中,需要使用 transition-group 组件把v-for循环的列表包裹起来:
<div id="app">
<input type="text" v-model="txt" @keyup.enter="add">
<transition-group tag="ul" name="list">
<li v-for="(item, i) in list" :key="i">{{item}}</li>
</transition-group>
</div>
3. 定义 VM中的结构:
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
txt: '',
list: [1, 2, 3, 4]
},
methods: {
add() {
this.list.push(this.txt);
this.txt = '';
}
}
});
列表的排序过渡
`<transition-group>` 组件还有一个特殊之处。不仅可以进入和离开动画,**还可以改变定位**。要使用这个新功能只需了解新增的 `v-move` 特性,**它会在元素的改变定位的过程中应用**。
`v-move` 和 `v-leave-active` 结合使用,能够让列表的过渡更加平缓柔和:
.v-move{
transition: all 0.8s ease;
}
.v-leave-active{
position: absolute;
}
定义Vue组件:
什么是组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可;
组件化和模块化的不同:
模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;
创建组件的方式:
// 1.1 使用 Vue.extend 来创建全局的Vue组件
// var com1 = Vue.extend({
// template: '<h3>这是使用 Vue.extend 创建的组件</h3>' // 通过 template 属性,指定了组件要展示的HTML结构
// })
// 1.2 使用 Vue.component('组件的名称', 创建出来的组件模板对象)
// Vue.component('myCom1', com1)
// 如果使用 Vue.component 定义全局组件的时候,组件名称使用了 驼峰命名,则在引用组件的时候,需要把 大写的驼峰改为小写的字母,同时,两个单词之前,使用 - 链接;
// 如果不使用驼峰,则直接拿名称来使用即可;
// Vue.component('mycom1', com1)
// Vue.component 第一个参数:组件的名称,将来在引用组件的时候,就是一个 标签形式 来引入 它的
// 第二个参数: Vue.extend 创建的组件 ,其中 template 就是组件将来要展示的HTML内容
Vue.component('mycom1', Vue.extend({
template: '<h3>这是使用 Vue.extend 创建的组件</h3>'
}))