Vue.directive 自定义指令
demo
图片加载完毕之前是一个随机的颜色块,之后设置器背景为该图片
// initImg
// import Vue from 'vue'
export default {
data () {
return {
imgs: [
{
url: 'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=412581619,2356057617&fm=27&gp=0.jpg'
},
{
url: 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2773798747,893160708&fm=27&gp=0.jpg'
},
{
url: 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2310380780,3374798962&fm=27&gp=0.jpg'
},
{
url: 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1670658008,1121581517&fm=27&gp=0.jpg'
}
]
}
},
directives: {
img: {
bind: function (el, binding, vnode) {
const r = Math.floor(Math.random() * 256)
const g = Math.floor(Math.random() * 256)
const b = Math.floor(Math.random() * 256)
let color = `rgb(${r},${g},${b})`
el.style.backgroundColor = color
var img = new Image()
img.src = binding.value
// 图片加载完毕之后
img.onload = function () {
el.style.backgroundImage = 'url(' + binding.value + ')'
}
}
}
},
methods: {
// rgb颜色
_colorRGB () {
const r = Math.floor(Math.random() * 256)
const g = Math.floor(Math.random() * 256)
const b = Math.floor(Math.random() * 256)
return `rgb(${r},${g},${b})`
},
// rgba颜色
_colorRGBA () {
const r = Math.floor(Math.random() * 256)
const g = Math.floor(Math.random() * 256)
const b = Math.floor(Math.random() * 256)
const alpha = Math.random()
return `rgba(${r}, ${g}, ${b}, ${alpha})`
}
}
}
.imgBox{
width: 100%;
}
.imgBox .img-item{
display: block;
width: 100%;
height: 200px;
margin-bottom: 4px;
}
跟随鼠标移动的指令
练习:自定义指令#itany div{
width: 100px;
height: 100px;
position:absolute;
}
#itany .hello{
background-color:red;
top:0;
left:0;
}
#itany .world{
background-color:blue;
top:0;
right:0;
}
Vue.directive('drag',function(el){
el.οnmοusedοwn=function(e){
//获取鼠标点击处分别与div左边和上边的距离:鼠标位置-div位置
var disX=e.clientX-el.offsetLeft;
var disY=e.clientY-el.offsetTop;
// console.log(disX,disY);
//包含在onmousedown里面,表示点击后才移动,为防止鼠标移出div,使用document.onmousemove
document.οnmοusemοve=function(e){
//获取移动后div的位置:鼠标位置-disX/disY
var l=e.clientX-disX;
var t=e.clientY-disY;
el.style.left=l+'px';
el.style.top=t+'px';
}
//停止移动
document.οnmοuseup=function(e){
document.οnmοusemοve=null;
document.οnmοuseup=null;
}
}
});
var vm=new Vue({
el:'#itany',
data:{
msg:'welcome to itany',
username:'alice'
},
methods:{
change(){
this.msg='欢迎来到南京网博'
}
}
});
Vue.extend() 扩展实例构造器
demo
// 实现了一个简单的组件
// 显示一个姓名,点击可以跳转
Documentvar author = Vue.extend({
template: '
{{authorName}}
',data () {
return {
authorName: 'zjj',
authorUrl: 'http://www.jspang.com'
}
}
})
//new author().$mount('author'); // 挂载到这个标签
new author().$mount('#author'); // 挂载到这个标签
extend构造过程
Vue.extend的作用
Vue.extend常和Vue的组件配合在一起使用。简单点说:Vue.extend是构造一个组件的语法器,你给这个构造器预设一些参数,而这个构造器给你一个组件,然后这个组件你就可以用到Vue.component这个全局注册方法里,也可以在任意Vue模板里使用这个构造器。
// 实现效果同上
Document// 【1】 vue.extend 构造一个组件
var author = Vue.extend({
template: '
{{authorName}}
',data () {
return {
authorName: 'zjj',
authorUrl: 'http://www.jspang.com'
}
}
})
// 【2】通过component全局注册了一下,即可使用了
Vue.component('my-com', author);
var Vue = new Vue({
el: '#app'
})
// 也可以是
Document// 【1】 vue.extend 构造一个组件
var author = Vue.extend({
template: '
{{authorName}}
',data() {
return {
authorName: 'zjj',
authorUrl: 'http://www.jspang.com'
}
}
})
// 【2】通过component全局注册了一下,即可使用了
Vue.component('my-com', {
template: '
{{authorName}}
',data() {
return {
authorName: 'zjj',
authorUrl: 'http://www.jspang.com'
}
}
});
var Vue = new Vue({
el: '#app'
})
Vue.component()会注册一个全局的组件,其会自动判断第二个传进来的是Vue继续对象(Vue.extend)还是普通对象({...}),如果传进来的是普能对象的话会自动调用Vue.extend,所以你先继承再传,还是直接传普通对象对Vue.component()的最终结果是没差的。
理解Vue.extend()和Vue.component()是很重要的。由于Vue本身是一个构造函数(constructor),Vue.extend()是一个继承于方法的类(class),参数是一个包含组件选项的对象。它的目的是创建一个Vue的子类并且返回相应的构造函数。而Vue.component()实际上是一个类似于Vue.directive()和Vue.filter()的注册方法,它的目的是给指定的一个构造函数与一个字符串ID关联起来。之后Vue可以把它用作模板,实际上当你直接传递选项给Vue.component()的时候,它会在背后调用Vue.extend()。
vue.extend构造的其实是一个vue构造函数的一个子类、它的参数是一个包含组件选项的对象。其中data 必须是一个函数
import Vue from 'vue
// 【1】 一个包含组件选项的对象
var component = {
props: {
active: Boolean,
propOne: String
},
template: `
see me if active
data () {
return {
text: 0
}
},
mounted() {
console.log('comp mounted');
}
}
// 【2】创建一个子类
var comVue = Vuew.extend(component);
// 【3】实例化一个子类
new comVue({
el: '#root,
propsData: {
propOne: 'xxx'
},
data : {
text: '123'
},
mounted () {
console.log('instance mounted');
}
})
Vue.set()
{{item.message}}
点我试试
var vm2=new Vue({
el:"#app2",
data:{
items:[
{message:"Test one",id:"1"},
{message:"Test two",id:"2"},
{message:"Test three",id:"3"}
]
},
methods:{
btn1Click:function(){
this.items.push({message:"动态新增"});//为data中的items动态新增一条数据
}
}
});
上诉demo利用数组的变异方法来实现数组的增减。但是我们却无法做到对某一条数据的修改。这时候就需要Vue的内置方法来帮忙了~
{{item.message}}
动态赋值
为data新增属性
var vm2=new Vue({
el:"#app2",
data:{
items:[
{message:"Test one",id:"1"},
{message:"Test two",id:"2"},
{message:"Test three",id:"3"}
]
},
methods:{
btn2Click:function(){
// 【1】 改变某一个索引项的值
Vue.set(this.items, 0, {message: 'Meils', id: '20'});
// 下面的这样改是无法成功的,因为Vue无法调用到
// this.items[0]={message:"Change Test",id:'10'}
//
},
btn3Click:function(){
// 【2】 往后面添加值
var len = this.items.length;
Vue.set(this.items, len, {message: 'sss', id:'30'})
}
}
});
调用方法:Vue.set( target, key, value )
target:要更改的数据源(可以是 对象 或者 数组 )
key:要更改的具体数据
value :重新赋的值
当写惯了JS之后,有可能我会想改数组中某个下标的中的数据我直接this.items[XX]就改了,如
// 下面的这样改是无法成功的,因为Vue无法检测到数组数据的改变
// this.items[0]={message:"Change Test",id:'10'}
原因:
由于Javascript的限制,Vue不能自动检测以下变动的数组。
当你利用索引直接设置一个项时,vue不会为我们自动更新。
当你修改数组的长度时,vue不会为我们自动更新
Tip: Vue.set()在methods中也可以写成this.$set()
生命周期
vue生命周期学习{{message}}
var vm = new Vue({
el: '#app',
data: {
message: 'Vue的生命周期'
},
beforeCreate: function() {
console.group('------beforeCreate创建前状态------');
console.log("%c%s", "color:red" , "el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //undefined
console.log("%c%s", "color:red","message: " + this.message)
},
created: function() {
console.group('------created创建完毕状态------');
console.log("%c%s", "color:red","el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeMount: function() {
console.group('------beforeMount挂载前状态------');
console.log("%c%s", "color:red","el : " + (this.$el)); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
mounted: function() {
console.group('------mounted 挂载结束状态------');
console.log("%c%s", "color:red","el : " + this.$el); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeUpdate: function () {
console.group('beforeUpdate 更新前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
updated: function () {
console.group('updated 更新完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
beforeDestroy: function () {
console.group('beforeDestroy 销毁前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
destroyed: function () {
console.group('destroyed 销毁完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message)
}
})
依次分析
beforeCreate
刚刚实例化了一下new Vue()
created
数据data绑定完毕,事件初始化完毕
此时还是没有el选项
beforeMounted
初始化el完毕,数据data绑定完毕,但是还是通过{{message}}进行占位的,因为此时还有挂在到页面上,还是JavaScript中的虚拟DOM形式存在的。
挂载 dom 并 模板编译过程:
1. 首先会判断对象是否有el选项。如果有的话就继续向下编译,如果没有el选项,则停止编译,也就意味着停止了生命周期,直到在该vue实例上调用vm.$mount(el)。
2. 然后进行模板编译
mounted
虚拟dom替换为真实的dom数据结构
beforeMouted 和 mounted的区别
beforeUpdate
updated
beforeDestroy
钩子函数在实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed
钩子函数在Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。