Vue3 高级语法以及自定义组件

1 .render函数

1. 1 h函数

  • h() 函数是一个用于创建vnode 的一个函数;
  • 其实更准备的命名是createVNode() 函数,但是为了简便在Vue将之简化为h() 函数;

h()函数如何使用呢?它接受三个参数:

第一个参数

在这里插入图片描述
第二个参数

在这里插入图片描述

第三个参数
在这里插入图片描述
注意事项:

  • 如果没有props,那么通常可以将children作为第二个参数传入;
  • 如果会产生歧义,可以将null作为第二个参数传入,将children作为第三个参数传入;

1 .1 .1 h()函数的基本使用

1 .render函数选项中使用; =>没有template模板

<script>
  import { h } from 'vue';

  export default {
    render() {
      return h("h2", {class: "title"}, "Hello Render")
    }
  }
</script>
<style scoped>
</style>

2 . setup函数选项中使用(setup本身需要是一个函数类型,函数再返回h函数创建的VNode)

在这里插入图片描述

  • 两张方式实现计数器
<script>
  import { h } from 'vue';

  export default {
    data() {
      return {
        counter: 0
      }
    },
    render() {
      return h("div", {class: "app"}, [
        h("h2", null, `当前计数: ${this.counter}`),
        h("button", {
          onClick: () => this.counter++
        }, "+1"),
        h("button", {
          onClick: () => this.counter--
        }, "-1"),
      ])
    }
  }
</script>
<style scoped>
</style>
<script>
  import { ref, h } from 'vue';

  export default {
    setup() {
      const counter = ref(0);
      return () => {
        return h("div", {class: "app"}, [
          h("h2", null, `当前计数: ${counter.value}`),
          h("button", {
            onClick: () => counter.value++
          }, "+1"),
          h("button", {
            onClick: () => counter.value--
          }, "-1"),
        ])
      }
    }
  }
</script>

1 .1 .2 h()函数中组件与插槽的使用

App.vue

<script>
  import { h } from 'vue';
  import HelloWorld from './HelloWorld.vue';
  export default {
    render() {
      return h("div", null, [
        h(HelloWorld, null, {
          default: props => h("span", null, `app传入到HelloWorld中的内容: ${props.name}`)
        })
      ])
    }
  }
</script>

HelloWord.vue'

<script>
  import { h } from "vue";

  export default {
    render() {
      return h("div", null, [
        h("h2", null, "Hello World"),
        this.$slots.default ? this.$slots.default({name: "coderwhy"}): h("span", null, "我是HelloWorld的插槽默认值")
      ])
    }
  }
</script>

1 .2 jsx语法糖

1 .2 .1 jsx的配置(旧版本)

  • 安装Babel支持Vue的jsx插件:
npm install @vue/babel-plugin-jsx -D
  • 在babel.config.js配置文件中配置插件:
    在这里插入图片描述
    在这里插入图片描述

1 .2 .2 jsx计数器案例

<script>
  export default {
    data() {
      return {
        counter: 0
      }
    },
    render() {
      const increment = () => this.counter++;
      const decrement = () => this.counter--;

      return (
        <div>
          <h2>当前计数: {this.counter}</h2>
          <button onClick={increment}>+1</button>
          <button onClick={decrement}>-1</button>
        </div>
      )
    }
  }
</script>

1 .2 .3 jsx组件的使用

App.vue

<script>
  import HelloWorld from './HelloWorld.vue';
  export default {
    data() {
      return {
        counter: 0
      }
    },
    render() {
      const increment = () => this.counter++;
      const decrement = () => this.counter--;
      return (
        <div>
          <h2>当前计数: {this.counter}</h2>
          <button onClick={increment}>+1</button>
          <button onClick={decrement}>-1</button>
          <HelloWorld>
          </HelloWorld>
        </div>
      )
    }
  }
</script>
<style lang="scss" scoped>
</style>

HelloWord.vue

<script>
  export default {
    render() {
      return (
        <div>
          <h2>HelloWorld</h2>
          {this.$slots.default ? this.$slots.default(): <span>哈哈哈</span>}
        </div>
      )
    }
  }
</script>

<style scoped>

</style>

2 .指令的生命周期

在这里插入图片描述
参考代码

<template>
  <div>
    <button v-if="counter < 2" v-why.aaaa.bbbb="'coderwhy'" @click="increment">当前计数: {{counter}}</button>
  </div>
</template>

<script>
  import { ref } from "vue";

  export default {
    // 局部指令
    directives: {
      why: {
        created(el, bindings, vnode, preVnode) {
          console.log("why created", el, bindings, vnode, preVnode);
          console.log(bindings.value);
          console.log(bindings.modifiers);
        },
        beforeMount() {
          console.log("why beforeMount");
        },
        mounted() {
          console.log("why mounted");
        },
        beforeUpdate() {
          console.log("why beforeUpdate");
        },
        updated() {
          console.log("why updated");
        },
        beforeUnmount() {
          console.log("why beforeUnmount");
        },
        unmounted() {
          console.log("why unmounted");
        }
      }
    },
    setup() {
      const counter = ref(0);
      const increment = () => counter.value++;

      return {
        counter,
        increment
      }
    }
  }
</script>

<style scoped>

</style>

3 .自定义组件

  • 在Vue中,代码的复用和抽象主要还是通过组件;
  • 通常在某些情况下,你需要对DOM元素进行底层操作,这个时候就会用到自定义指令;

自定义指令分为两种:

  • 自定义局部指令:组件中通过directives 选项,只能在当前组件中使用;
  • 自定义全局指令:app的directive 方法,可以在任意组件中被使用;

3 .1自定义组件元素挂载完成后可以自定获取焦点

  • 普通的方式
<template>
  <div>
    <input type="text" ref="input">
  </div>
</template>

<script>
  import { ref, onMounted } from "vue";

  export default {
    setup() {
      const input = ref(null);

      onMounted(() => {
        input.value.focus();
      })

      return {
        input
      }
    }
  }
</script>
<style scoped>
</style>
  • 局部自定义指令
<template>
  <input type="text" v-focuss="" value="取值" /></template>

<script>
// import {directives} from 'vue';
export default {
  // 自定义组件实现聚焦 
	// 自定义组件利用directives方法实现的实现
  directives: {
		// 自定义组件的方式
    focuss: {
			// 挂载前
			mounted(el,any,anyy,anyyy) {
				el.focus() 
				// 第三个数值可以拿去值
				console.log(el,any,anyy,anyyy);
				console.log(anyy.props.value);
				
			}
		},
  },
};
</script>
<style>
</style>
  • 全局自定义组件使用
app.directive("focus", {
  mounted(el, bindings, vnode, preVnode) {
    console.log("focus mounted");
    el.focus();
  }
})

3 .2 指令的参数和修饰符

  • 如果我们指令需要接受一些参数或者修饰符应该如何操作呢?

    • info是参数的名称;
  • aaa-bbb是修饰符的名称;

  • 后面是传入的具体的值;

  • 在我们的生命周期中,我们可以通过bindings 获取到对应的内容:
    在这里插入图片描述
    在这里插入图片描述

3 .3自定义指令实现时间的转换

  • 时间戳的显示需求:

    • 在开发中,大多数情况下从服务器获取到的都是时间戳;
    • 我们需要将时间戳转换成具体格式化的时间来展示;
    • 在Vue2中我们可以通过过滤器来完成;
    • 在Vue3中我们可以通过计算属性(computed) 或者自定义一个方法(methods) 来完成;
    • 其实我们还可以通过一个自定义的指令来完成;
  • 实现一个可以自动对时间格式化的指令v-format-time

    • 这里我封装了一个函数,在首页中我们只需要调用这个函数并且传入app即可;
      在这里插入图片描述
  • 具体代码实现
    App.vue
<template>
  <h2 v-format-time="'YYYY/MM/DD'">{{timestamp}}</h2>
  <h2 v-format-time>{{timestamp}}</h2>
</template>

<script>
  export default {
    // 创建时间戳进行返回
    setup() {
      const timestamp = 1624452193;

      return {
        timestamp
      }
    },
    mounted() {
      console.log("app mounted");
    }
  }
</script>
<style scoped>

</style>

index.js=>入口

import registerFormatTime from './format-time';

export default function registerDirectives(app) {
  registerFormatTime(app);
}

format-time.js

import dayjs from 'dayjs';

export default function(app) {
  app.directive("format-time", {
    created(el, bindings) {
      bindings.formatString = "YYYY-MM-DD HH:mm:ss";
      if (bindings.value) {
        bindings.formatString = bindings.value;
      }
    },
    mounted(el, bindings) {
      const textContent = el.textContent;
      let timestamp = parseInt(textContent);
      if (textContent.length === 10) {
        timestamp = timestamp * 1000
      }
      el.textContent = dayjs(timestamp).format(bindings.formatString);
    }
  })
}

main.js

import { createApp } from 'vue'
import App from './03_自定义指令/App.vue'
import registerDirectives from './directives'
const app = createApp(App);

registerDirectives(app);
// app.directive("focus", {
//   mounted(el, bindings, vnode, preVnode) {
//     console.log("focus mounted");
//     el.focus();
//   }
// })
app.mount('#app');

4 .Vue插件

通常我们向Vue全局添加一些功能时,会采用插件的模式,它有两种编写方式:

  • 对象类型:一个对象,但是必须包含一个install 的函数,该函数会在安装插件时执行;
  • 函数类型:一个function,这个函数会在安装插件时自动执行;

插件可以完成的功能没有限制,比如下面的几种都是可以的:

  • 添加全局方法或者property,通过把它们添加到config.globalProperties 上实现;
  • 添加全局资源:指令/过滤器/过渡等;
  • 通过全局mixin 来添加一些组件选项;
  • 一个库,提供自己的API,同时提供上面提到的一个或多个功能;

4 .1插件的编写方式

对象类型

在这里插入图片描述
函数类型

在这里插入图片描述

  • 具体的访问过程
    在这里插入图片描述
    plugins.Object.js
export default {
  install(app,el) {
		   app.config.globalProperties.$name = 'coderwhy'
			
	},
};
  • App.vue中访问自定义组件的值
<template>
  {{ $name }}
</template>

<script>
 import { getCurrentInstance } from "vue";
export default {
  // 在setup中拿取自定义组件中的属性值
	// setup没有this的绑定拿取不到自定义组件的值因此需要在导入app=>getCurrentInstance
	setup(props) {
		const app=getCurrentInstance()
		//进行取值
		console.log(app.appContext.config);
	},
	// 生命周期中拿取自定义组件中的值

  created() {
	  console.log(this.$name)
	},
};
</script>

<style>
</style>

插件的编写具体方法

5 .Teleport的使用

在这里插入图片描述
实例代码效果
在这里插入图片描述
在这里插入图片描述

5 .1和组件结合使用

  • teleport也可以和组件结合一起来使用:
  • 因此可以在teleport 中使用组件,并且也可以给他传入一些数据;
    在这里插入图片描述
    在这里插入图片描述

5 .2 多个teleport的使用

  • 如果我们将多个teleport应用到同一个目标上(to的值相同),那么这些目标会进行合并:
    在这里插入图片描述
    在这里插入图片描述
  • 具体封装代码实现

App.vue的代码

<template>
  <div class="app">
    <teleport to="#why">
      <h2>当前计数</h2>
      <button>+1</button>
      <hello-world></hello-world>
    </teleport>
    <teleport to="#why">
      <span>呵呵呵呵</span>
    </teleport>
  </div>
</template>
<script>
  import HelloWorld from './HelloWorld.vue';
  export default {
    components: {
      HelloWorld
    },
  }
</script>
<style scoped>
</style>

HelloWord.vue代码

<template>
  <div>
    <h2>Hello World</h2>
  </div>
</template>

<script>
  export default {
    
  }
</script>

<style scoped>

</style>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值