vue-day05----自定义指令(directive)、render和template的区别、mixin混入、Vue.use()、Vue.extend()、Vue.filter()、vue中的数据流向
### 自定义指令 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中组件通讯的数据流向?
在组件通讯的时候数据的流向是单向数据流。
在组件通信的时候父组件传递给子组件的状态,子组件只允许做访问,不能做修改。如果需要做修改则需要在自己内部保存一份再进行修改。因为如果子组件改变了父组件的状态,会导致数据流难以理解。
好记性不如写博客