自定义钩子函数
除了Vue 内置指令外,Vue也支持我们自定义注册指令,当我们觉得什么功能注册为指令更方便使用的时候,我们就可以自己去注册
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
- inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
- componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
- unbind:只调用一次,指令与元素解绑时调用
nextTick
nextTick() 等待下一次 DOM 更新刷新的工具方法
我们有时会考虑到现在正在写的业务代码能否操作vue对象的实例,所以我们需要一个工具 就是让我们写的代码 无论在哪里写 都希望它是组件加载完了以后才运行的,而nextTick() 正好解决了这个问题
当我们在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个“tick”才一起执行。这也是为了确保每个组件无论发生多少状态改变,都仅执行一次更新
局部和全局
全局:所有组件共同的功能(指令,过滤器,组件)
局部:只有当前组件的功能(指令,过滤器,组件)
<script src='https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.js'></script>
<style type="text/css">
<body>
.app {
width: 400px;
background-color: gold;
}
.box1 {
width: 200px;
height: 200px;
background-color: darkorange;
margin: 20px;
}
.box11{
width: 120px;
height: 50px;
background-color: hotpink;
margin: 20px;
}
</style>
<div id='app' class="app">
<Box1></Box1>
<p>{{msg|box1tool}}</p>
<p v-color2="'blue'" v-color>{{msg|alltool1}}</p>
</div>
<script>
Vue.filter("alltool1",function(str){
return str+"全局"
})
Vue.directive("color",function(el,obj){
el.style.color=obj.value||"red"
})
var vm = new Vue({
el: '#app',
data: {
msg:"appdata"
},
components: {
Box1: {
template: template: `<div class="box1">
<p>{{msg|box1tool}}</p>
<p v-color2="'blue'" v-color>{{msg|alltool1}}</p>
<Box11></Box11>
</div>`,
data: function() {
return {
msg: "hello"
}
},
filters: {
box1tool(str) {
return str + "局部"
}
},
directives:{
color2:{
inserted(el,obj){
el.style.background=obj.value||"red"
}
}
},
components:{
Box11:{
template:`<div class="box11">
<h1>box11</h1>
</div>`
}
}
}
}
})
</script>
</body>
组件
什么是组件?
组件是Vue中的一个重要概念,是一个可以重复使用的Vue实例,它拥有独一无二的组件名称,它可以扩展HTML元素,以组件名称的方式作为自定义的HTML标签。
因为组件是可复用的Vue实例,所以它们与new Vue()接收相同的选项,例如data,computed、watch、methods以及生命周期钩子等。
仅有的例外是像el这样根实例特有的选项。
什么是复用?
把一些公共的模块抽取出来,然后写成单独的的工具组件或者页面,在需要的页面中就直接引入即可。那么我们可以将其抽出为一个组件进行复用
例如 页面头部、侧边、内容区,尾部,上传图片,等多个页面要用到一样的就可以做成组件,提高了代码的复用率
定义组件
<template>
<div>
<h1>nav1组件</h1>
</div>
</template>
<script>
export default {
data:function(){
return {
msg:"hello"
}
},
}
</script>
<style>
</style>
引入并使用组件
<script src='https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.js'></script>
</head>
<body>
<div id='app'>
<Nav1></Nav1>
</div>
<script type="module">
import Nav1from "./com/Nav1.js"
var vm = new Vue({
el: '#app',
components:{
Nav1
}
})
</script>
使用Nav1,就能在页面上显示 nav1组件 这几个字了
注册组件需要主要的点
- 可以这样引入
import Box1 from "@/Nav1.vue"
,@代表目录 - 注册的组件名不能跟vue中的和原生DOM的重名,注册的名字是驼峰 使用时就用连字符
- 注册的组件 使用时可以用双标签也可以用单标签: 如果有插槽必须用双标签
<script>
//1.@代表了src目录的意思
import Box1 from "@/Nav1.vue"
//2.注册的组件名不能跟vue中的和原生DOM的重名,注册的名字是驼峰 使用时就用连字符
import BoxDiv2 from "@/com/BoxDiv2.vue"
//3.注册的组件 使用时可以用双标签也可以用单标签: 如果有插槽必须用双标签
export default {
components: {
Nav1
}
}
</script>
如果 .vue 的script注释了 在打包的时候 vue的打包环境 会帮我们把这个文件解析为一个对象 然后给这个对象添加一个template属性 值为解析的页面模板,也就是说 .vue文件中 可以不要<style>
和<script>
但是不能不写<template>
<style>
可以写多个
每一个组件内部只能有一个根元素 也不要再根元素上写v-for,写了就循环出来多个根元素了,就会报错
注册组件的属性
对于components对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。
属性有两种写法:简单声明和详细描述:
-
简单声明
props:[“prop1”,“prop2”] -
对属性做详细的描述
props: {
propA: Number, // 基础的类型检查 (`null` 匹配任何类型)
propB: [String, Number], // 多个可能的类型
propC: { type: String,
required: true // 必填的字符串
},
propD: { type: Number,
default: 100 // 带有默认值的数字
},
propE: { type: Object, // 带有默认值的对象或者数组填Array
default: function () { // 不建议直接填对象(因为对象直接量会一直占用内存),一般使用工厂函数,调用时才创建对象节省资源(面试)
return { message: 'hello' }
}
},
propF: {
validator: function (value) {// 自定义验证函数返回为true就代表数据符合我们规定
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
对象形式的 props 声明不仅可以一定程度上作为组件的文档,而且如果其他开发者在使用你的组件时传递了错误的类型,也会在浏览器控制台中抛出警告
Css样式的覆盖解决
在vue中当我们引入多个 .vue 文件是,就有可能style里面的类名重复,造成样式的错乱,我们可以直接在style标签这里加一个 scoped 就解决啦
像这样:<style scoped="scoped">
等号后面是一个布尔值,写什么都可以
添加了scoped函数,在运行时就会为类名加上一个独一无二的值,就不会存在类名重复问题,就不会造成样式混乱了