Vue3 高级语法以及自定义组件
在Vue中,代码的复用和抽象主要还是通过组件;通常在某些情况下,你需要对DOM元素进行底层操作,这个时候就会用到自定义指令;组件中通过directives 选项,只能在当前组件中使用;app的directive 方法,可以在任意组件中被使用;普通的方式setup() {局部自定义指令。
·
文章目录
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即可;
- 具体代码实现
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>
更多推荐
已为社区贡献2条内容
所有评论(0)