Vue.directive 自定义指令
demo
图片加载完毕之前是一个随机的颜色块,之后设置器背景为该图片
// initImg
<template>
<!-- 自定义指令 -->
<!-- 图片加载之前是随机颜色背景,图片加载完成之后设置背景为图片 -->
<div class="imgBox">
<div class="img-item" v-img="item.url" v-for="(item, index) in imgs" :key="index"></div>
</div>
</template>
<script>
// 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})`
}
}
}
</script>
<style scoped>
.imgBox{
width: 100%;
}
.imgBox .img-item{
display: block;
width: 100%;
height: 200px;
margin-bottom: 4px;
}
</style>
跟随鼠标移动的指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>练习:自定义指令</title>
<script src="./vue.min.js"></script>
<style>
#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;
}
</style>
</head>
<body>
<div id="itany">
<div class="hello" v-drag>itany</div>
<div class="world" v-drag>网博</div>
</div>
<script>
Vue.directive('drag',function(el){
el.onmousedown=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.onmousemove=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.onmouseup=function(e){
document.onmousemove=null;
document.onmouseup=null;
}
}
});
var vm=new Vue({
el:'#itany',
data:{
msg:'welcome to itany',
username:'alice'
},
methods:{
change(){
this.msg='欢迎来到南京网博'
}
}
});
</script>
</body>
</html>
Vue.extend() 扩展实例构造器
demo
// 实现了一个简单的组件
// 显示一个姓名,点击可以跳转
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./vue.min.js"></script>
</head>
<body>
<div id="author"></div>
<!-- <author></author> -->
<script>
var author = Vue.extend({
template: '<p><a :href="authorUrl">{{authorName}}</a></p>',
data () {
return {
authorName: 'zjj',
authorUrl: 'http://www.jspang.com'
}
}
})
//new author().$mount('author'); // 挂载到这个标签
new author().$mount('#author'); // 挂载到这个标签
</script>
</body>
</html>
- extend构造过程
Vue.extend的作用
Vue.extend常和Vue的组件配合在一起使用。简单点说:Vue.extend
是构造一个组件的语法器
,你给这个构造器预设一些参数,而这个构造器给你一个组件,然后这个组件你就可以用到Vue.component
这个全局注册方法里,也可以在任意Vue模板里使用这个构造器。
// 实现效果同上
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./vue.min.js"></script>
</head>
<body>
<div id="app">
<my-com></my-com>
</div>
<script>
// 【1】 vue.extend 构造一个组件
var author = Vue.extend({
template: '<p><a :href="authorUrl">{{authorName}}</a></p>',
data () {
return {
authorName: 'zjj',
authorUrl: 'http://www.jspang.com'
}
}
})
// 【2】通过component全局注册了一下,即可使用了
Vue.component('my-com', author);
var Vue = new Vue({
el: '#app'
})
</script>
</body>
</html>
// 也可以是
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./vue.min.js"></script>
</head>
<body>
<div id="app">
<my-com></my-com>
</div>
<script>
// 【1】 vue.extend 构造一个组件
var author = Vue.extend({
template: '<p><a :href="authorUrl">{{authorName}}</a></p>',
data() {
return {
authorName: 'zjj',
authorUrl: 'http://www.jspang.com'
}
}
})
// 【2】通过component全局注册了一下,即可使用了
Vue.component('my-com', {
template: '<p><a :href="authorUrl">{{authorName}}</a></p>',
data() {
return {
authorName: 'zjj',
authorUrl: 'http://www.jspang.com'
}
}
});
var Vue = new Vue({
el: '#app'
})
</script>
</body>
</html>
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: `<div>
<input type="text" v-model="text">
<span v-show="active">see me if active</span>
</div>`,
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()
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app2">
<!--想了解这里key的作用请访问:(https://cn.vuejs.org/v2/api/#key)-->
<p v-for="item in items" :key="item.id">
{{item.message}}
</p>
<!--@click等价于v-on:click-->
<button class="btn" @click="btn1Click()">点我试试</button><br/>
</div>
<script src="../extend/vue.min.js"></script>
<script>
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动态新增一条数据
}
}
});
</script>
</body>
</html>
上诉demo利用数组的变异方法来实现数组的增减。但是我们却无法做到对某一条数据的修改。这时候就需要Vue的内置方法来帮忙了~
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app2">
<p v-for="item in items" :key="item.id">
{{item.message}}
</p>
<button class="btn" @click="btn2Click()">动态赋值</button><br/><br/>
<button class="btn" @click="btn3Click()">为data新增属性</button>
</div>
<script src="../extend/vue.min.js"></script>
<script>
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'})
}
}
});
</script>
</body>
</html>
调用方法: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()
生命周期
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue生命周期学习</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
<div id="app">
<h1>{{message}}</h1>
</div>
</body>
<script>
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)
}
})
</script>
</html>
- 依次分析
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 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。