Vue.js 3.0 学习笔记(九)组件和组合API

编程入门 行业动态 更新时间:2024-10-08 06:28:56

Vue.js 3.0 学习笔记(九)组件和<a href=https://www.elefans.com/category/jswz/34/1769978.html style=组合API"/>

Vue.js 3.0 学习笔记(九)组件和组合API

一、组件是什么

组件是Vue中的一个重要概念,它是一种抽象,是一个可以复用的Vue实例

二、组件的注册

1、全局注册

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>全局注册组件</title>
</head>
<body>
<div id="app"><!--使用my-component组件--><my-component></my-component>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({});vmponent('my-component', {data(){return{message:"红罗袖里分明见"}},template: `<div><h2>{{message}}</h2></div>`});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

2、局部注册

局部注册的组件只能在一个Vue实例中使用

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>局部注册组件</title>
</head>
<body>
<div id="app">库房还剩<button-counter></button-counter>台。
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>const MyComponent = {data() {return {num: 1000}},template: `<button v-on:click="num--">{{ num }}</button>`			}//创建一个应用程序实例const vm= Vue.createApp({components: {ButtonCounter: MyComponent}});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

三、使用prop向子组件传递数据

1、prop基本用法

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>使用prop属性向子组件传递数据</title>
</head>
<body>
<div id="app"><blog-content date-title="庭院深深深几许,云窗雾阁春迟。"></blog-content>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({});vmponent('blog-content', {props: ['dateTitle'],//date-title就像data定义的数据属性一样template: '<h3>{{ dateTitle }}</h3>',//在该组件中可以使用“this.dateTitle”这种形式调用prop属性created(){console.log(this.dateTitle);}});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

传递title属性到子组件

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>传递title属性到子组件</title>
</head>
<body>
<div id="app"><blog-content v-bind:date-title="content"></blog-content>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({//该函数返回数据对象data(){return{content:"玉瘦檀轻无限恨,南楼羌管休吹。"}}});vmponent('blog-content', {props: ['dateTitle'],template: '<h3>{{ dateTitle }}</h3>',});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

组件与组件之间传递

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>组件之间传递数据</title>
</head>
<body>
<div id="app"><!--使用blog-content组件--><blog-content></blog-content>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({ });vmponent('blog-content', {// 使用blog-title组件,并传递contenttemplate: '<div><blog-title v-bind:date-title="title"></blog-title></div>',data:function(){return{title:"明朝准拟南轩望,洗出庐山万丈青。"}}});vmponent('blog-title', {props: ['dateTitle'],template: '<h3>{{ dateTitle }}</h3>',});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

传递多个值

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>传递多个值</title>
</head>
<body>
<div id="app"><!--使用blog-content组件--><blog-content></blog-content>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({ });vmponent('blog-content', {// 使用blog-title组件,并传递contenttemplate: '<div><blog-title :name="name" :price="price" :num="num"></blog-title></div>',data:function(){return{name:"苹果",price:"6.88元",num:"2800公斤"}}});vmponent('blog-title', {props: ['name','price','num'],template: '<ul><li>{{name}}</li><li>{{price}}</li><li>{{num}}</li></ul> ',});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

2、单向数据流

父组件的prop属性的更新会向下流动到子组件中,但是反过来不行
而且父组件的更新时,所有子组件都会刷新成最新的值,因此子组件内部改变prop属性
有两种方法可以改变子组件中的prop属性

  1. 在data中定义一个属性来承接prop数据,后续改变就是在内部修改,不用改变prop数据
  2. 使用计算属性将prop数据进行转换后使用

3、prop验证

通过name:String这样的方式进行验证传递的数据类型是否符合要求

4、非prop的属性

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>非prop的属性</title>
</head>
<body>
<style>.bg1{background: #C1FFE4;}.bg2{width: 120px;}</style>
<div id="app"><!--使用blog-content组件--><input-con class="bg2" type="password"></input-con>
</div><!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({ });vmponent('input-con', {template: '<input class="bg1" type="text">',});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

四、子组件向父组件传递数据

1、监听子组件事件

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>子组件要向父组件传递数据</title>
</head>
<body>
<div id="app"><parent></parent>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({ });vmponent('child', {data:function () {return{info:{name:"哈密瓜",price:"8.66",num:"2600公斤"}}},methods:{handleClick(){//调用实例的$emit()方法触发自定义事件date2,并传递infothis.$emit("date2",this.info)},},template:'<button v-on:click="handleClick">显示子组件的数据</button>'});vmponent('parent', {data:function(){return{name:'',price:'',num:'',}},methods:{// 接收子组件传递的数据childDate(info){this.name=info.name;this.price=info.price;this.num=info.num;}},template:`<div><child v-on:date2="childDate"></child><ul><li>{{name}}</li><li>{{price}}</li><li>{{num}}</li></ul></div>`});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

2、将原生事件绑定到组件

原生事件:就是最原始的事件,没有经过包装的事件

3、.sync修饰符

本来是为peop属性的“双向绑定”提供了一个缩写,但我这里无效
但是直接用v-model就可以用

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>设计购物的数量</title>
</head>
<body>
<div id="app">父组件:购买{{counter}}件<!--在子组件中通过$emit注册事件,将数据作为参数传入,在父组件中通过$event接收--><child v-bind:value="counter" v-on:update:value="counter=$event"></child><child v-model:value.sync="counter"></child>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({data(){return{counter:0}}});vmponent('child', {data:function () {return{count:this.value}},props:{value:{type:Number,default:0}},methods:{handleClick(){this.$emit("update:value",++this.count)},},template:`<div><span>子组件:购买{{value}}件</span><button v-on:click="handleClick">增加</button></div>`});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

五、插槽

1、插槽基本用法

可以理解为占位符

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>插槽基本用法</title>
</head>
<body>
<div id="app"><page>如今直上银河去,同到牵牛织女家。</page>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({});vmponent('page', {template:`<div><slot></slot></div>`});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

2、编译作用域

<parent>{{name}}</parent>

代码中的name属性是在父组件作用域下解析的,而不是parent组件的作用域
记住:父组件模板里的所有内容都是在父级作用域中编译的,子组件模板里的所有内容都是在子作用域中编译的

3、默认内容

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>设置插槽的默认内容</title>
</head>
<body>
<div id="app"><page>流年莫虚掷,华发不相容。</page>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({ });vmponent('page', {template:`<button type="submit"><slot>Submit</slot></button>`});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

4、命名插槽

通过命名不同的插槽插入不同的内容

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>命名插槽</title>
</head>
<body>
<div id="app"><page-layout><template #header><h2 align='center'>书河上亭壁</h2></template><template v-slot:main><h3>岸阔樯稀波渺茫,独凭危槛思何长。</h3><h3>萧萧远树疏林外,一半秋山带夕阳。</h3></template><template v-slot:footer><p align='right'>经典古诗</p></template></page-layout>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({ });vmponent('page-layout', {template:`<div class="container"><header><slot name="header"></slot></header><main><slot name="main"></slot></main><footer><slot name="footer"></slot></footer></div>`});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

5、作用域插槽

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>访问插槽的内容</title>
</head>
<body>
<div id="app"><page-layout>
<!--        default代表slot的默认名字,后面的slotProps表示获取的对象info,名字可以随便取--><template v-slot:default="slotProps"><!--这个才表示赋值显示-->{{slotProps.values.name}}</template></page-layout>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({ });vmponent('page-layout', {data:function(){return{info:{name:'苹果',price:8.86,city:"深圳"}}},template:`<button><slot v-bind:values="info"><!--这个slot内部的表示默认-->{{info.city}}  </slot></button>`});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

6、解构插槽prop

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>解构插槽prop</title>
</head>
<body>
<div id="app"><current-verse><!--其实就是重命名verse为poetry--><template v-slot="{verse:poetry}">{{poetry.firstContent }}</template></current-verse>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({ });vmponent('currentVerse', {template: ' <span><slot :verse="verse">{{ verse.secondContent }}</slot></span>',data:function(){return {verse: {firstContent: '此心随去马,迢递过千峰。',secondContent: '野渡波摇月,空城雨翳钟。'}}}});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

六、组合API和回调函数

组合API:解决选项式API例如methods、computed等在组件变大时难以阅读和理解的问题
回调函数:将函数作为一个参数传递给其他代码,JS是由事件驱动的语言,因此常常需要监听其他事件然后执行,然而JS不会等待事件响应后才进行下一个事件,而是直接执行下一个,根据响应的速度进行相应的反应,所以回调正是确保一段代码执行完毕之后再执行另一段代码的方式。

function add(num1, num2, callback){var sum = num1 + num2;callback(sum);
}function print(num){console.log(num);
}
//将print作为一个参数,在add函数内部进行调用,这就是回调
add(1, 2, print);        //=>3
function first(){
// 模拟代码延迟setTimeout( function(){console.log(1);}, 500 );
}function second(){console.log(2);
}first();
second();

根据上述代码,你会发现控制台上输出的首先是2,然后才是1,这并不是JS不按顺序执行,而是因为second先响应,JS不会等待first响应后才去响应second

七、setup()函数

setup()函数是组件内部使用组合API的入口点
setup()函数在创建组件之前执行,因此在setup()函数中没有this,所以除了props之外,用户将无法访问组件中声明的任何属性——本地状态、计算属性或方法等

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>setup()函数</title>
</head>
<body>
<div id="app"><post-item :post-content="content"></post-item>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>//创建一个应用程序实例const vm= Vue.createApp({ data(){return {content: '月浅灯深,梦里云归何处寻。'}}});vmponent('PostItem', {//声明propsprops: ['postContent'],setup(props){//相当于watch,都是用监听的,不过它会自动收集依赖,当函数内部存在属性变动时,会自动进行回调Vue.watchEffect(() => {console.log(props.postContent);})},template: '<h3>{{ postContent }}</h3>'});//在指定的DOM元素上装载应用程序实例的根组件vm.mount('#app');
</script>
</body>
</html>

八、响应式API

1、reactive()方法和watchEffect()方法

reactive():一种创建响应式对象的方法,其内部就是利用Proxy API实现的,其作用是接收一个普通对象然后返回该普通对象的响应式代理,进而实现双向数据绑定,要注意返回的代理对象不等于原始对象
watchEffect():该方法接收一个函数作为参数,会立即运行该函数,同时响应式地跟踪其依赖项,并在依赖项发生修改时重新运行该函数

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>reactive()方法和watchEffect()方法</title>
</head>
<body>
<div id="app"><post-item :post-content="content"></post-item>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>const {reactive, watchEffect} = Vue;const state = reactive({count: 0});watchEffect(() => {document.body.innerHTML = `商品库存为: ${state.count}台。`})
</script>
</body>
</html>

可以直接进行修改

2、ref()方法

ref():该方法接受一个原始值,返回一个响应式和可变的响应式对象

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>ref()方法</title>
</head>
<body>
<div id="app"><post-item :post-content="content"></post-item>
</div>
<!--引入vue文件-->
<script src="@next"></script>
<script>const {ref, watchEffect} = Vue;const state = ref(0)watchEffect(() => {//注意这里是state.valuedocument.body.innerHTML = `商品库存为: ${state.value}台。`})
</script>
</body>
</html>

3、readonly()方法

readonly():该方法为原始对象创建一个只读属性,从而防止该对象在注入的地方发生变化

4、computed()方法

computed():该方法接受一个getter函数,并为getter返回的值返回一个不可变的响应式对象
和之前的computed类似

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>computed()方法</title>
</head>
<body>
<div id="app"><p>原始字符串: {{ message }}</p><p>反转字符串: {{ reversedMessage }}</p>
</div>
<script src="@next"></script>
<script>const {ref, computed} = Vue;const vm = Vue.createApp({setup(){const message = ref('人世几回伤往事,山形依旧枕寒流');const reversedMessage = computed(() =>message.value.split('').reverse().join(''));return {message,reversedMessage}}}).mount('#app');
</script>
</body>
</html>

5、watch()方法

watch():该方法需要监听特定的数据源,并在单独的回调函数中应用
同vue2

九、Vue3访问组件的方式

vue2访问组件实例的属性,可以直接访问组件的实例
而vue3访问组件实例会通过组件代理对象,而不是直接访问组件实例

十、综合案例——使用组件创建树状项目分类

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>树状项目分类</title>
</head>
<body>
<div id="app"><category-component :list="categories"></category-component>
</div>
<script src="@next"></script>
<script>const CategoryComponent = {name: 'catComp',props: {list: {type: Array}},template: `<ul><!-- 如果list为空,表示没有子分类了,结束递归 --><template v-if="list"><li v-for="cat in list">{{cat.name}}<!--递归调用自己--><catComp :list="cat.children"/></li></template></ul>`}const app = Vue.createApp({data(){return {categories: [{name: '网站开发技术', children: [{name: '前端开发技术', children: [{name: 'HTML5开发技术'}, {name: 'Javascript开发技术'},{name: 'Vue.js开发技术'}]}, {name: 'PHP后端开发技术'}]},{name: '网络安全技术', children: [{name: 'Linux系统安全'}, {name: '代码审计安全'},{name: '渗透测试安全'}]}]}},components: {CategoryComponent}}).mount('#app');
</script></body>
</html>

更多推荐

Vue.js 3.0 学习笔记(九)组件和组合API

本文发布于:2024-02-13 21:13:25,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1760553.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:组合   学习笔记   组件   js   Vue

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!