### 自定义指令 directive
全局自定义指令:Vue.directive()
局部自定义指令:directives
directive(参数一,参数二)
参数一:指令名称
参数二:指令的配置项,可以是函数,也可以是对象
函数:
参数一:使用当前指令的元素
参数二:指令的详细信息
{
modifiers:修饰符(只要自定义指令后面跟了修饰符,modifiers对象中就有值,为true),
value:指令的值(假设指令这样写:<div v-test="'aaa'"></div>,那么value就是aaa)
}
指令的作用:操作DOM元素
步骤:
①src下新建utils/utils.js:
import Vue from "vue";
/**
* v-test指令:
* <div v-test="'发发发'"></div>
* 相当于
* <div>发发发</div>
*
*/
Vue.directive("test",(el,{value})=>{
el.innerText=value;
});
/**
* 设置背景颜色的指令
*
*/
Vue.directive("backgroundColor",(el,{value,...rest})=>{
el.style.backgroundColor=value;
});
/**
* 阻止浏览器默认事件:v-event.prev
*
*/
Vue.directive("event",(el,{modifiers})=>{
let {prev}=modifiers;
el.addEventListener("contextmenu",(e)=>{
if(prev){
e.preventDefault();
}
});
});
/**
* 自动聚焦
*
*/
Vue.directive("focus",{
// 获取光标在inserted中操作,此时元素已经插入到父节点了
inserted(el){
el.focus();
}
});
/**
* 第一个参数是指令名称,第二个参数如果是一个函数,这个函数是指令要做的事情,如果是一个对象,这个对象是指令的配置项。
*
*
*/
Vue.directive("wql",{
bind(){
// 当前元素使用当前指令的时候会被调用,只会调用一次,用来做初始化
console.log("bind")
},
inserted(){
// 当使用指令的元素被插入到父节点(#app)的时候会被触发
console.log("inserted")
},
update(){
// 只要当前元素不被移除,其他操作几乎都会触发这2个生命周期,先触发update后触发componentUpdate
// 虚拟DOM只要涉及到元素的隐藏、显示(display)值的改变、内容的改变等都会触发虚拟DOM更新
console.log("update")
},
componentUpdated(){
console.log("componentUpdate")
},
unbind(){
// 当只用指令的元素被卸载的时候会执行,简单的说就是当前元素被移除的时候
console.log("unbind")
}
});
/**
* v-drag
*
*/
Vue.directive("drag",(el,{modifiers,value})=>{
if(value){
var disX,disY;
var {l,t} = modifiers;
el.style.position = "absolute";
el.addEventListener("mousedown",mousedown)
function mousedown(e){
disX = e.offsetX;
disY = e.offsetY;
document.addEventListener("mousemove",move)
document.addEventListener("mouseup",up)
}
function move(e){
var x = e.clientX - disX;
var y = e.clientY - disY;
if((l&&t) || (!l&&!t)){
el.style.left = x + 'px';
el.style.top = y + 'px';
return;
}
if(l){
el.style.left = x + 'px';
return;
}
if(t){
el.style.top = y + 'px';
return;
}
}
function up(){
document.removeEventListener("mousemove",move)
document.removeEventListener("mouseup",up)
}
}
});
②main.js中引入:
import "./utils/utils.js";
③App.vue中使用自定义指令:
<div v-test="'发发发'" v-backgroundColor.not="'blue'"></div>
<div v-test="'阻止浏览器默认事件'" v-backgroundColor="'yellow'" v-event.prev></div>
<input type="text" v-focus>
指令的生命周期:
bind():当元素只用当前指令的时候会被调用,只会调用一次,用来做初始化
inserted():当使用指令的元素被插入到父节点(#app)的时候会被触发
update():只要当前元素不被移除,其他操作几乎都会触发这2个生命周期,先触发update后触发componentUpdate。虚拟DOM什么时候更新:只要涉及到元素的隐藏、显示(display)值的改变、内容的改变等都会触发虚拟DOM更新
componentUpdate():组件更新
unbind():当使用指令的元素被卸载的时候会执行,就是当前元素被移除的时候
### render和template的区别
template----html的方式做渲染
render----js的方式做渲染
render(提供)是一种编译方式
render里有一个函数h,这个h的作用是将单文件组件进行虚拟DOM的创建,然后再通过render进行解析。
h就是createElement()方法:createElement(标签名称,属性配置,children)
template也是一种编译方式,但是template最终还是要通过render的方式再次进行编译。
区别:
1、render渲染方式可以让我们将js发挥到极致,因为render的方式其实是通过createElement()进行虚拟DOM的创建。逻辑性比较强,适合复杂的组件封装。
2、template是类似于html一样的模板来进行组件的封装。
3、render的性能比template的性能好很多
4、render函数优先级大于template
### mixin 混入
通过mixins引入组件后,会给当前组件额外扩展一些属性和方法,简单的说就是给组件额外添加了一个BUFF
封装插件的时候用mixin
mixin----全局使用
mixins----局部使用
步骤:
①utils下新建mixin.js:
export default {
// new Vue()中的配置项都可以在这里加
data(){
return{
title:"我是额外提供的一个属性"
}
},
created() {
console.log("我是一个buff")
}
}
②App.vue中引入:
import Mixin from "./utils/mixin.js";
③添加mixins属性:
mixins:[Mixin],
此时在created中就多一个console.log打印,在App.vue页面可以直接使用title属性,就和写在自己的data中一样。
### Vue.use()
Vue.use()是用来使用插件的,当前插件如果导出的是一个函数,那么这个函数就会被当做install方法。如果当前插件导出的是一个对象,那么这个对象必须提供一个install方法,因为Vue.use()在使用这个插件的时候会给install方法提供一个Vue构造函数。
注:所有的插件都创建了一个install方法,再将install方法导出。
使用场景:如果在编写插件的时候通过外部的方式来引入Vue的时候会使这个插件变得特别大,此时需要用到Vue.use(),它的作用就是给插件传递一个vue。
步骤:
①src下新建plugins/wql.js:
// 如果导出一个函数,这个函数会被当做是install方法,同时Vue.use()会给这个函数传递Vue的构造函数,不用引入直接就有
// export default (Vue)=>{
// console.log(Vue)
// }
// 如果导出一个对象,这个对象必须要提供install方法,同时Vue.use()会给这个方法传递Vue的构造函数
export default {
install(Vue){
console.log(Vue)
}
}
②main.js中引入并使用wql.js:
import wql from "./plugins/wql.js";
Vue.use(wql); // 打印vue的构造函数
### Vue.extend()
作用:让编写好的组件可以当成方法使用,就是将ui组件转换为js组件。
步骤:
①src下新建publics/index.vue和publics/index.js文件:
在index.vue中写好组件,在index.js中引入再通过Vue.extend()继承,转换成js组件
import messageBox from "./index.vue";
import Vue from 'vue';
// options对象是Message()中的参数对象
export default (options)=>{
// 继承Vue,将js对象来继承Vue,来转换成js组件,这个js组件可以被放在页面的任何地方
let MessageBox=Vue.extend(messageBox);
let vmMessage=new MessageBox({
el:document.createElement("div"),
// 这里是继承的Vue,所以有和vue一样的配置项,可以写data、methods、生命周期...
}
// $mount()返回一个对象,其中有$el,$el就是赋给el的div
document.body.appendChild(vmMessage.$mount().$el);
}
②main.js中引入并使用:
import Message from "./plugins/message/index.js";
Vue.use(Message);
此时页面上就已经显示了组件,因为install方法是自动执行的。
③不在main.js中引入,直接在需要使用的组件(App.vue)中引入:
import Message from "./plugins/message/index.js";
然后在created()中执行 Message(); 就会在页面上显示出来,Message()中可以写一个{},将属性和方法传递给options。
### Vue.filter()
作用:过滤数据
语法:
全局:
Vue.filter("过滤器名",(参数一,参数二)=>{});
参数一:需要过滤的数据
参数二:传递的数据
局部:
filters:{
过滤器名(){
}
}
使用:{{username|过滤器名()}}
步骤:
(1)时间过滤器
①声明一个全局过滤器
Vue.filter("date",(data,icon)=>{
let year=(new Date(data)).getFullYear();
let month=(new Date(data)).getMonth()+1;
let day=(new Date(data)).getDate();
var icon=icon||"/";
return `${year}${icon}${month}${icon}${day}`;
});
②实例中设置一个time:
let vm=new Vue({
el:"#app",
data:{
time:(new Date()).getTime()
}
});
③管道符进行使用:
{{time|date("-")}}
(2)图片尺寸过滤器
①data中将imgUrl引入:
data(){
return{
imgUrl:"http://p0.meituan.net/w.h/movie/2c24eb6a84a92b9ba837967851bec9462844109.jpg"
}
}
②声明局部filters:
filters:{
imgReplace(data,wh){
// 将字符串 "w.h" 替换为 "170.280"
return data.replace(/w.h/,wh);
}
}
③页面中使用:
<img :src="imgUrl|imgReplace('170.280')">
### Question:
vue中组件通讯的数据流向?
在组件通讯的时候数据的流向是单向数据流。
在组件通信的时候父组件传递给子组件的状态,子组件只允许做访问,不能做修改。如果需要做修改则需要在自己内部保存一份再进行修改。因为如果子组件改变了父组件的状态,会导致数据流难以理解。
