目录
Vue.directive
官方原话
在 Vue2.0 中,代码复用和抽象的主要形式是组件。
然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作
,这时候就会用到自定义指令
。
1、概括
1.1 语法:全局注册
// id:自定义指令的名称,
// [definition]:钩子函数
Vue.directive(id,[definition])
demo示例
// main.js
// 全局注册
Vue.directive('focus',{
// 当绑定元素插入到 DOM 中
inserted: function(el) {
el.focus();
}
})
new Vue({
router,
store,
render: h => h(App),
}).$mount('#app')
// 页面引入
<template>
<div class="content">
<input type="text" v-focus/>
</div>
</template>
1.2 钩子函数
一个指令定义对象可以提供如下几个钩子函数(均为可选):
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update
:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。componentUpdated
:指令所在组件的 VNode 及其子 VNode 全部更新后调用。unbind
:只调用一次,指令与元素解绑时调用。
// 注册
Vue.directive('my-directive',{
bind: function () {},
inserted: function () {},
update: function () {},
componentUpdated: function () {},
unbind: function() {}
})
1.3 钩子函数的参数
指令钩子函数会被传入以下参数:
el
:指令所绑定的元素,可以用来直接操作 DOM。binding
:一个对象,包含以下 property:name
:指令名,不包括v-
前缀。value
:指令的绑定值,例如:v-my-directive="1 + 1"
中,绑定值为2
。oldValue
:指令绑定的前一个值,仅在update
和componentUpdated
钩子中可用。无论值是否改变都可用。expression
:字符串形式的指令表达式。例如v-my-directive="1 + 1"
中,表达式为"1 + 1"
。arg
:传给指令的参数,可选。例如v-my-directive:foo
中,参数为"foo"
。modifiers
:一个包含修饰符的对象。例如:v-my-directive.foo.bar
中,修饰符对象为{ foo: true, bar: true }
。
vnode
:Vue 编译生成的虚拟节点。oldVnode
:上一个虚拟节点,仅在update
和componentUpdated
钩子中可用。
注意:除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的
dataset
来进行。
(1) demo示例
<template>
<div class="content">
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
</div>
</template>
<script>
export default {
name: 'Content',
data(){
return{
message: 'hello!'
}
},
directives: {
demo:{
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
}
}
}
</script>
(2) 页面显示
1.4 函数简写
在很多时候,你可能想在bind
和update
时触发相同行为,而不关心其它的钩子。比如这样写:
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value
})
2、常用案例
2.1 输入框聚焦
2.2 绑定背景颜色
2.3 文字显示
<template>
<div>
<div id="app"><input v-focus /></div>
<hr>
<p style="width:200px;height:200px" v-pin='colors'>trying</p>
<hr>
<div id="app" v-demo:foo.a.b="message"></div>
</div>
</template>
<script>
import Vue from "vue";
// 1、输入框聚焦
Vue.directive("focus", {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus();
},
});
// 2、绑定背景颜色
Vue.directive('pin', function(el, binding) { //背景颜色
el.style.background = binding.value
})
// 3、文字显示
Vue.directive('demo', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
})
export default {
name: "directive",
data() {
return {
colors:"",//定义变量接收
message:'left',
}
},
created(){
this.colors="pink"
}
}
</script>
2.4 使用vue.directive的图片加载
<template>
<div>
<div v-img="url" style="width: 500px; height: 500px;"></div>
</div>
</template>
<script>
import Vue from "vue"; //需要引入
Vue.directive("img", {
bind:function(el){
var color = Math.floor(Math.random() * 1000000);
el.style.backgroundColor = "#" + color;
},
inserted: function (el, binding) {
var img = new Image();
img.src = binding.value;
img.onload = function () {
el.style.backgroundImage = "url(" + binding.value + ")";
};
},
});
export default {
name: "directive",
data() {
return {
url: "../../../1.jpg",//据具体图片存储文件夹而定
};
},
};
</script>
2.5 自定义指令实现拖拽
// 全局自定义指令(必须在实例之前)
/*
参数1:指令的名称
参数2:指令实现的函数
*/
Vue.directive('drag', (el, { value, modifiers }) => {
// el代表使用该指令的元素
el.onmousedown = function (e) {
// console.log("s");
var disx = e.offsetX
var disy = e.offsetY
// 阻止浏览器的默认事件
e.preventDefault()
document.onmousemove = function (e) {
var x = e.clientX - disx
var y = e.clientY - disy
// 如果表达式的结果是false,就不拖拽
if (!value) {
return
}
// 修饰符
if (modifiers.x) {
el.style.left = x + 'px'
}
// 修饰符
if (modifiers.y) {
el.style.top = y + 'px'
}
if (!(modifiers.x && !modifiers.y) && value) {
el.style.left = x + 'px'
el.style.top = y + 'px'
}
}
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
}
}
})
<template>
<div id="app">
<!-- //y轴拖拽: 全拖拽,不是y轴 -->
<div class="box" v-drag.y="show">y</div>
<!-- //x轴拖拽 -->
<div class="box" v-drag.x="show">x</div>
</div>
</template>
<script>
export default {
name: 'directive',
data () {
return {
show: true
}
}
}
</script>
<style scoped>
.box {
width: 100px;
height: 100px;
background: red;
position: absolute;
}
</style>
Vue.filter
官方原话
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。
过滤器分:全局过滤器和局部过滤器,重点说下全局过滤器,因为全局过滤器在项目中使用频率非常高!
1、概括
1.1 语法:全局注册
// 第一个参数:是过滤器的ID(即名字),
// 第二个参数:一个处理函数,过滤器要实现的功能在这个函数中定义。
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.toUpperCase();
})
1.2 语法:使用过滤器
<div>{{ message | capitalize }}</div>
1.3 demo示例
<div id="app">
<input type="text" v-model="message">
{{ message | capitalize }}
</div>
<script>
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.toUpperCase();
})
new Vue({
el:'#app',
data:{
message:'java'
}
})
</script>
2、实际开发场景
在实际开发中,全局过滤器经常会被在数据(比如时间、日期的装饰)上边,通常我们会把处理函数给抽离出去,统一放在一个.js文件中,下边用代码说下.
//filter.js 文件
let filter_price = function (val,...params){
return "¥" + val
}
let filter_date = function (){
return "2019/10/20" + val
}
export {filter_price,filter_date} //导出过滤函数
2.1 main.js循环注册过滤器
//main.js
//下边是2种导入方式,推荐第一种
import * as _filter from './filters/filter'
// import {filter_price,filter_date} from './filters/filter'
console.log(_filter)
Object.keys(_filter).forEach(item=>{
Vue.filter(item,_filter[item])
})
new Vue({
router,store,
render: h => h(App),
}).$mount('#app')
2.2 在vue文件中使用过滤器
<template>
<div>
<h1>{{price | filter_price}}</h1>
</div>
</template>
<script>
export default {
name:'news',
data(){
return{
price:1200
}
}
}
</script>
Vue.filter:
模板中 文本后边需要添加管道符号( | )
作为分隔,
管道符 | 后边是文本的处理函数,
- 处理函数的
第一个参数
是:管道符前边的——文本内容
,- 如果处理函数还需要传递其他参数,则从
第二个参数依次往后是传递的参数
。
this.$set
官方原话
向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。
它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = ‘hi’)
简单理解:就是添加/修改一个响应式对象属性的。
语法:
this.$set(数组/对象,索引,新值)
1、基本使用
<template>
<div>
<ul>
<li v-for="item in arr">{{ item }}</li>
</ul>
<button @click="soBtn">排序</button>
<button @click="reBtn">翻转</button>
<button @click="jBtn">截取前3个</button>
<button @click="upBtn">点击改掉第一个元素的值</button>
</div>
</template>
<script>
export default {
data() {
return {
arr: [3, 15, 10, 1, 19, 32],
};
},
methods: {
soBtn() {
this.arr.sort();
},
reBtn() {
this.arr.reverse();
},
jBtn() {
this.arr = this.arr.slice(0, 3);
},
upBtn() {
// this.arr[0] = "老李"; // 页面无变化 - vue无法监测数组里值的改变
// 可以使用数组提供的方法
// 数据目标, 索引, 新值
// Vue.set(this.arr, 0, "老李"); // 静态方法set
this.$set(this.arr, 0, "老李"); // 实例方法$set
},
},
};
</script>
this.$forceUpdate
官方原话
迫使 Vue 实例重新渲染。
注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
简单理解:数据没有响应式更新时,也可以通过this.$forceUpdate()强制刷新
<template>
<div>
<p>{{ userInfo.name }}</p>
<button @click="updateName">修改userInfo</button>
</div>
</template>
<script>
export default {
data () {
return {
userInfo: { name: '小明' }
}
},
methods: {
updateName () {
this.userInfo.name = '小红'
}
}
}
</script>
<style scoped>
</style>
在updateName
函数中,我们尝试给userInfo
对象修改值,发现页面其实并没有变化.
那这时候有两种解决方法:
方法一:
methods:{
updateName(){
this.userInfo.name='小红'//在此时,确实已经将userInfo对象修改完成
console.log(this.userInfo.name);//输出结果: 小红
this.$forceUpdate();//在这里,强制刷新之后,页面的结果变为'小红'
}
}
方法二:
methods:{
updateName(){
this.$set('userInfo',name,'小红');
}
}