vue组件销毁时取消监听事件
<template>
<div>
<button></button>
</div>
</template>
<script>
export default {
mounted(){
this.charts = echarts.init(this.$el)
//请求数据 赋值一系列操作。。。
//监听窗口发生改变 resize 组件
window.addEventListener('resize',this.$_handleResizeChart)
//通过hook监听组件销毁钩子函数 并取消监听事件
this.$once('hook:beforeDestroy',()=>{
window.removeEventListener('resize',this.$_handleResizeChart)
})
},
created(){
},
methods:{
$_handleResizeChart(){
}
}
}
</script>
<style lang="scss" scoped>
</style>
外部监听组件或第三方组件的生命周期函数
<template>
<div>
<!-- 通过@hook:updated监听组件的updated生命钩子函数 -->
<!-- 组件的所有生命周期钩子都可以通过@hook:钩子函数名 来监听触发 -->
<custom-select @hook:updated="$_handleSelectUpdated"></custom-select>
</template>
<script>
import customSelect from '../components/custom-select'
export default {
data(){
return{
}
},
components:{
customSelect
},
methods:{
$_handleSelectUpdated(){
console.log('custom-select组件的updated钩子函数被触发')
}
}
}
</script>
状态管理小项目不用Vuex而是Vue.observable手写一个状态管理
store.js
/*
* @Author: your name
* @Date: 2020-06-26 11:58:28
* @LastEditTime: 2020-06-26 12:04:38
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \新建文件夹\vues\src\components\store.js
*/
import Vue from 'vue'
// 通过Vue.observable创建一个可响应的对象
export const store = Vue.observable({
userInfo: {},
roleIds: []
})
// 通过mutations,修改属性
export const mutations = {
setUserInfo(userInfo) {
store.userInfo = userInfo
},
setRoleIds(roleIds) {
store.roleIds = roleIds
}
}
组件中使用
<template>
<div>
<!-- 小型的项目不需要使用vuex进行数据状态管理,可使用Vue.observable 手动打造一个Vuex -->
{{userInfo.name}}
</div>
</template>
<script>
import {store,mutations} from './store'
export default {
data(){
return {}
},
computed: {
userInfo(){
return store.userInfo
}
},
created() {
mutations.setUserInfo({name:'子轩'})
},
}
</script>
<style scoped>
</style>
Vue.extend + 单例模式去实现全局的loading
Vue.extend是一个全局的api
通过Vue.extend将组件转换为全局组件
可以开发一些全局的组件
customLoading.vue
<template>
<transition name="custom-loading-fade">
<!-- loadding蒙层 -->
<div v-show="visible" class="custom-loading-mask">
<div class="custom-loading-spinner">
<!-- 字体图标 -->
<i class="custom-spinner-icon"></i>
<!-- loadding上面的文字 -->
<p class="custom-loading-text">{{text}}</p>
</div>
</div>
</transition>
</template>
<script>
export default {
data(){
return{
text:"",
visible: false
}
},
}
</script>
<style scoped>
</style>
index.js 通过 (Vue.extend 改造组件)
import Vue from 'vue'
import LoadingComponent from './customLoading.vue'
// 通过Vue.extend将组件包装成一个子类
const LoadingConstructor = Vue.extend(LoadingComponent)
let loading = undefined
LoadingConstructor.prototype.close = function(){
// 如果loading有用 则去掉loading的引用
if(loading){
loading = undefined
}
// 先将组件隐藏
this.visible = false
//延迟300毫秒 等loading的关闭动画结束 销毁组件
setTimeout(()=>{
// 移除挂载的dom元素
//this.$el 是Vue实例关联的DOM元素
if(this.$el&&this.$el.parentNode){
this.$el.parentNode.removeChild(this.$el)
}
//调用组件的$destroy方法进行组件销毁
this.$destroy()
},300)
}
const Loading = (options={})=>{
//如果组件已渲染,则返回即可
if(loading){
return loading
}
// 要挂载的元素
let parent = document.body
// 组件属性
const ots = {
text:'',
...options
}
//通过构造函数初始化组件 相当于new Vue()
const instance = new LoadingConstructor({
el:document.createElement('div'),
data:ots
})
// 将loading元素挂载到parent上面
parent.appendChild(instance.$el)
// 显示loading
Vue.nextTick(()=>{
instance.visible = true
})
// 将组件实例赋值给loading
loading = instance
return instance
}
export default Loading
在页面中使用loading
<script>
import Loading from './index'
export default {
crated(){
const loading = Loading({text:'加载中...'})
// 三秒后关闭
setTimeout(()=>{
loading.close()
},3000)
}
}
</script>
开发V-loading指令
loading.js
import Vue from 'vue'
import LoadingComponent from './customLoading.vue'
// 使用Vue.extend构建组件子类
const LoadingConstructor = Vue.extend(LoadingComponent)
//定义一个名为loading的指令
Vue.directive('loading',{
// 只调用一次 在指令第一次绑定到元素时调用,可以在这里做一些初始化的设置
// @param {*}el 指令要绑定的元素
//@param{*}binding 指令传入的信息
//包括{name:'指令名称',value:'指令要绑定的值',arg:'指令参数 v-bind:text 对应text'}
bind(el,binding){
const instance = new LoadingConstructor({
el:document.createElement('div'),
data:{}
})
el.appendChild(instance.$el)
el.instance = instance
Vue.nextTick(()=>{
el.instance.visible = binding.value
})
},
/**
* @description: 所在组件的VNode更新时调用
* @param {*} el
* @param {*} binding
*/
update(el,binding){
// 通过对比值的变化判断Loading是否显示
if(binding.oldValue !== binding.value){
el.instance.visible = binding.value
}
},
/**只调用一次 在指令与元素解绑时调用
* @param {*} el
*/
unbind(el){
const mask = el.instance.$el
if(mask.parentNode){
mask.parentNode.removeChild(mask)
}
el.instance.$destroy()
el.instance = undefined
}
})
在元素上面使用
<template>
<div v-loading="visible">
</div>
</template>
<script>
import Loading from './index'
export default {
data(){
return{
visible: false
}
},
craeted(){
this.visible = true
fetch().then(()=>{
this.visible = false
})
}
}
</script>
<style scoped>
</style>
函数式组件
函数式组件与普通组件的区别
1 函数式组件需要在声明组件时指定functional
2 函数式组件没有this 由render函数的第二个参数代替
3 函数式组件没有生命周期 不能使用计算属性 watch 等等
4 函数式组件不能通过$emit 对外暴露事件 调用事件只能通过context.listeners.click的方式调用外部传入的事件
5 因为函数式组件是没有实例化的 所以通过ref去引用组件 实际上引用的是HTMLElement
6 函数式组件的props 可以不用显示声明 所以没在props声明的属性都会被自动隐式解析为prop,
普通组件的所有未声明的属性都被解析到$attrs里面,并自动挂载到组件根元素上面(可通过inheritAttrs)属性禁止
render函数式是Vue使用JSX的写法
<script>
export default {
// 设置functional属性指定组件为函数式组件
functional:true,
props:{
avator:{
type: String,
default:''
}
},
/**
* @param {*} h
* @param {*} context 函数式组件没有this props slots等都在context上面挂着
*/
render(h,context){
let {props} = context
if(props.avator){
return <img src={props.avator}></img>
}
return <img src="default-avator.png"></img>
}
}
</script>
- 最主要最关键的原因是函数式组件不需要实例化,无状态,没有生命周期,所以渲染性能要好于普通组件
- 函数式组件结构比较简单,代码结构更清晰
不用JSX的函数式组件
<template functional>
<!-- 在template上添加functional属性 -->
<!-- 生命函数式组件 -->
<img :src="props.src?props.avatar:'default-avatar.png'" >
<!-- // 根据函数式特点 可以省略props的声明 -->
</template>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。