Vue从入门到精通

Created: 15 Dec 2025

Author:  Chen Xie

Vue从入门到精通

摘要

视频链接

教程:https://www.bilibili.com/video/BV1rgnFzMEp4

视频备份:移动硬盘,尚未上传。

主要内容

  1. v-if : 销毁渲染 , 占用资源
  2. v-show : 对属性的设置, display: none 隐藏
  3. v-model : 双向绑定数据, 一般用于表单
  4. v-bind: 可简写:title , 单向数据
  5. computed : 计算属性, 利用缓存的机制, 提高效率, 减少资源占用
  6. 修饰符的作用: 对输入值的限制约束 , 按键响应 等等
  7. v-for 遍历数据
  8. v-text ,v-html:区别于 v-html显而易见可以解析 html标签元素

后续学习内容

详细记录

基础

04:Vue开发前的准备

npm init vue@latest 项目名,不要有大写

image

npm intall​ 可以用cnpm install替代(用国内镜像安装)

npm run dev 运行

05:目录结构

关键:src、vite.config.js

image

06:模板语法(开始编程、文本绑定``)

准备工作:

<template><!--html内容-->

</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				
			}
		}
	}
</script>

示例(App.vue文件)

<template>
  <h3>h3Title</h3>
  <p>{{ msg }}</p>
  <p>{{ number++ }}</p>
  <p>{{ ok ? 'yes' : 'no' }}</p>
  <p>{{ message.split("").reverse().join("") }}</p>
  <!-- <p>{{ var a=10 }}</p> -->
  <!-- <p>{{ if(ok){return message} }}</p> -->
  <p v-html="rawHtml"></p>
  <p>{{ rawHtml }}</p>
</template>

<script>
export default {
  data(){
    return{
      msg:"神奇的语法",
      number:10,
      ok:true,
      message:"大家好",
      rawHtml:"<a href='https://baidu.com'>百度链接</a>"
    }
  } 
}
</script>

07:模板语法-属性绑定v-bind:​或:

<template><!--html内容-->
 <!-- <div class="{{ msg }}">test</div> 不行-->
 <div v-bind:class="msg"  v-bind:title="dynamicTitle">test</div>
</template>

<!--js code-->
<script>
export default {
    data() {
        return {
            msg:"active",
            dynamicTitle:null
        }
    }
}
</script>

如果绑定的值是null​或者undifinded​,这个attribute会被移除。

因为v-bind:​很常用,所以可以简化成:

<div :class="msg"  :title="dynamicTitle">test</div>

实例:改变按钮的可否点击状态

image

绑定多个值

<template><!--html内容-->
 <div v-bind="objectAttrs"></div>
</template>

<!--js code-->
<script>
export default {
    data() {
        return {
            msg:"active",
            dynamicTitle:null,
            objectAttrs: {
                id: "appId",
                class: "appclass"
            }
        }
    }
}

08:条件渲染v-if​、v-else​、v-else-if​、v-show

v-if​和v-show比较

09:列表渲染v-for

<template><!--html内容-->
    <h3>列表渲染</h3>
    <!--一般案例-->
    <p v-for="item in names">{{ item }}</p>
    <!--默认还有index,of代替in-->
    <p v-for="(value,index) of names">{{index}}-{{ value }}</p>
    <!--模拟ajax返回值-->
    <div v-for="item in result">
        <p><a :href="item.url">{{ item.title }}</a></p>
    </div>
    <!--for也可以轮询key-value对-->
    <div v-for="(value,key,index) of usrInfo">
        <p>{{ index }}-{{ key }}-{{ value }}</p>
    </div>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				names:["AA","BB","CC"],
                result: [
                    {
                        "id":11,
                        "title":"AA",
                        "url":"https://baidu.com"

                    },
                    {
                        "id":22,
                        "title":"BB",
                        "url":"https://google.com"
                    },
                    {
                        "id":33,
                        "title":"CC",
                        "url":"https://quark.com"
                    }
                ],
                usrInfo:{
                    name:"owen",
                    age:20,
                    sex:""
                }
			}
		}
	}
</script>

10:通过key管理状态(对v-for的补充)

推荐在任何时候都要为v-for​提供一个key属性

<template><!--html内容-->
    <h3>Key属性添加到v-for中</h3>
    <p v-for="(item,index) in names" :key="index"></p>
	<!--不建议用index作为key-->
	<!--用数据对应的唯一ID作为key-->
	 <p v-for="(value,key,index) in result" :key="value.id"></p>
</template>

<!--js code-->
<script>
	export default {
        data() {
			return {
				names:["AA","BB","CC"],
				result: [
                    {
                        "id":11,
                        "title":"AA",
                        "url":"https://baidu.com"

                    },
                    {
                        "id":22,
                        "title":"BB",
                        "url":"https://google.com"
                    },
                    {
                        "id":33,
                        "title":"CC",
                        "url":"https://quark.com"
                    }
                ]
			}
		}
	}
</script>

11:事件处理v-on​或者@​,@click=“jsFunction”

<template><!--html内容-->
    <h3>内联事件处理器</h3>
    <button @click="count++">add</button>
    <p>9</p>

    <h3>方法事件处理器</h3>
    <button @click="addCount">add</button>
    <p></p>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				count:0,
                count2:0
			}
		},
        methods:{
            addCount(){
                this.count2 +=1
            }
        }
	}
</script>

12:事件传参:默认传入event​对象,传入变量​,指定传入事件$event

<template><!--html内容-->
    <h3>事件传参</h3>
    <button @click="addCount">add</button>
    <p>9</p>

    <p @click="getNameHandler(value,$event)" v-for="(value,index) of names" :key="index"></p>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				count:0,
                names:["owen","amy","frank"]
			}
		},
        methods:{
            //传递Event对象
            addCount(e){
                // console.log(e);
                e.target.innerHTML = "Add" + this.count;
                this.count +=1
            },
            getNameHandler(name,e){
                console.log(name);
                console.log(e);
            }
        }
	}
</script>

13:事件修饰符:.stop​、.prevent​、.once​、.enter

官方文档:https://cn.vuejs.org/guide/essentials/event-handling.html#event-modifiers

14:数组变化侦测(数组变化时,UI自动更新.push()​or不更新.concat()

更新:.push()​, .pop()​, .shift()​, .unshift()​, .splice()​, .sort()​, .reverse()

不更新:.filter()​、.concat()​、.slice()

<template><!--html内容-->
    <button @click="addListHandler">add</button>
    <ul>
        <li v-for="(value,index) in names" :key="index"></li>
    </ul>
    <button @click="combineNumHandler">合并数组</button>
    <h3>数据1</h3>
    <p v-for="(item,index) of num1" :key="index"></p>
    <h3>数据2</h3>
    <p v-for="(item,index) of num2" :key="index"></p>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				names:["bill","Mick","amy"],
                num1:[1,2,3,4],
                num2:[5,6,7,8]
			}
		},
        methods:{
            addListHandler(){
                //引起UI自动更新
                this.names.push("sakura")
                //不引起UI自动更新
                this.name.concat(["sakura"])
                console.log(names)
                //如果要更新需要
                this.name = this.name.concat(["sakura"])
            },
            combineNumHandler(){
                this.num1 = this.num1.concat(this.num2)
                // this.num1.push(this.num2)
            }
        }
	}
</script>

15:计算属性:(与函数的区别,只要值不变,计算属性不会重复运算,函数每次重新运算)

<template><!--html内容-->
    <!-- 不容易维护 -->
    <p ></p>
    <!-- 计算1次 -->
    <p></p>
    <p></p>
    <p></p>
    <!-- 计算3次 -->
    <p></p>
    <p></p>
    <p></p>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				testContent:{
                    name:"bill",
                    content:["AA","BB"]
                }
			}
		},
        computed:{
            hasValue(){
                return this.testContent.content.length > 0 ? 'Yes' : 'No'
            }
        },
        methods:{
            hasValueHandler(){
                return this.testContent.content.length > 0 ? 'Yes' : 'No'
            }
        }
	}
</script>

16:Class绑定::class=""中,可以绑定对象、数组

官方文档:https://cn.vuejs.org/guide/essentials/class-and-style.html#binding-html-classes

<template><!--html内容-->
    <!-- id不能解析,Class可以解析 -->
    <p :id="{ 'active':isActive,'hasError':hasError }" :class="{ 'active':isActive,'hasError':hasError }">Class样式绑定</p>
    <!-- 对象 -->
    <p :class="classObject">Class样式绑定2</p>
    <!-- 数组 -->
    <p :class="[arrActive, arrHasError]">Class样式绑定3</p>
    <!-- 数组里嵌套对象(不能对象里嵌套数组),不推荐,不好理解 -->
    <p :class="[ isActive? 'active' : '',{'hasError':hasError}]">Class样式绑定4</p>
    <button @click="showObjectHandler">check</button>
    <button @click="activeTrueHandler">activeTrue</button>
    <button @click="hasErrorTrueHandler">hasErrorTrue</button>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				isActive:true,
                hasError:true,
                classObject:{
                    'active':this.isActive,
                    'hasError':this.hasError
                },
                arrActive:'active', 
                arrHasError:'hasError',
                'active':true
			}
		},
        methods:{
            showObjectHandler(){
                console.log(this.classObject)
            },
            activeTrueHandler(){
                this.isActive=true
            },
            hasErrorTrueHandler(){
                this.hasError=true
            }
        },
        computed:{

        }
	}
</script>
<style>
.active{
    font-size:30px
}
.hasError{
    color:red;
}
</style>

17:Style绑定:真实使用推荐用class绑定,style权重太高,后期不好改。

18:侦听器

<!--选项式API-->
<template><!--html内容-->
<p></p>
<button @click="updateMsg">change msg</button>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				msg:'hello'
			}
		},
        methods:{
            updateMsg(){
                this.msg = 'hello vue3';
            }
        },
        computed:{
            
        },
        watch:{
            msg(newValue,oldValue){
                console.log(`newValue:${newValue},oldValue:${oldValue}`);
            }
        }
	}
</script>

19:表单绑定 v-model​、.lazy​、.trim​、.number

官方文档:https://cn.vuejs.org/guide/essentials/forms.html

<template><!--html内容-->
    <h3></h3>
    <form action="">
        <input type="text" v-model="msg">
        <p></p>
        <!--单个复选框的内容-->
        <div>Checked: </div>
        <input type="checkbox" id="checkbox" v-model="checked" />
        <!--多个复选框的内容-->
        <div>Checked names: </div>

        <input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
        <label for="jack">Jack</label>

        <input type="checkbox" id="john" value="John" v-model="checkedNames" />
        <label for="john">John</label>

        <input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
        <label for="mike">Mike</label>
        <!--lazy修饰符-->
        <div>
            <input type="text" v-model.lazy="msg2">
            <p></p>
        </div>
        
    </form>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				title:'表单双向绑定',
                msg:'',
                msg2:'',
                checked: false,
                checkedNames: []
			}
		},
        methods:{

        },
        computed:{
            
        },
        watch:{
        }
	}
</script>

20:模板引用 ref​、this.$refs(除非不得已,不要操作DOM,性能开销大)

<template><!--html内容-->
    <h3>模板引用</h3>
    <div ref="divRef"></div>
    <button @click="getElementHandler">修改Div</button>
    <p></p>
    <input type="text" ref="inputRef" />
    <button @click="getInputHandler">修改Div</button>
</template>

<!--js code-->
<script>

	export default {
		data (){
			return {
				msg:'hello vue3'
			}
		},
        methods:{
            getElementHandler(){
                console.log(this.$refs.divRef);
                this.$refs.divRef.style.color = 'red';
                this.$refs.divRef.innerHTML = 'dududu';
            },
            getInputHandler(){
                console.log(this.$refs.inputRef.value);
                this.$refs.inputRef.value = 'hello';
            }
        },
        computed:{
            
        },
        watch:{
            
        }
	}
</script>

组件结构

image

21:组件组成 style scoped(仅当前文件,不加就是全局样式)

官方文档:https://cn.vuejs.org/guide/essentials/component-basics.html

23:组件注册:全局main.jsvs局部

不推荐全局的场景:①没有实际被使用的;②使大型项目的依赖关系变得不明确,影响长期维护性

// main.js
import { createApp } from 'vue'
import App from './App.vue'

import RefDemo from './components/RefDemo.vue'
const app = createApp(App)

// 在这中间写组件注册
app.component('RefDemo',RefDemo)
//
app.mount('#app')

24:组件传参props,只能父传子,不能子传父

<!--Parent.vue-->
<template><!--html内容-->
    <h3>Parent</h3>
    <Child title="child of parent" :dynamic="msg"/>
</template>

<!--js code-->
<script setup>
import Child from './Child.vue';

</script>
<script>
	export default {
		data (){
			return {
				msg:'hello parent'
			}
		}
	}
</script>
<!--Child.vue-->
<template><!--html内容-->
    <h4>Child</h4>
    <p></p>
    <p></p>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				
			}
		},
        props:{
            title:String,
            dynamic:String
        }
	}
</script>

25:传参的数据类型(数字、数组、对象都可以)

26:传参Props校验、default​值的设置、required​必传项,不能通过this.参数=​来修改传来的Props里的参数(只读的)

<!--Child.vue-->
<template><!--html内容-->
    <h4>Child</h4>
    <p></p>
    <p></p>
	<p></p>
	<p v-for="(item,index) of names" :key="index"></p>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				
			}
		},
        props:{
            title:String,
            dynamic:{
				type:[Number,Array,Object], //任意都可以
				required:true  //必选项
			}
			age:{
				type:Number,
				default:0 //字符和数字可以声明默认值
			}
			//数组、对象的默认值,需要用函数返回值的形式。
			names: {
				type:Array,
				default() {
					return ["A1","B2"]
				}
			}
        }
	}
</script>

27:组件事件 $emit,实现参数“子传父”

<!--Parent-->
<template><!--html内容-->
    <h3>组件事件</h3>
    <ChildEvent @someEvent="getChildData"/>
    <p></p>
</template>

<!--js code-->
<script setup>
    import ChildEvent from './ChildEvent.vue';
</script>
<script>
	export default {
		data (){
			return {
				msg:""
			}
		},
        methods:{
            getChildData(data){
                this.msg = data;
            }
        }
	}
</script>
<!--Child-->
<template><!--html内容-->
    <h3>Child</h3>
    <button @click="emitParentEvent">触发传参</button>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				
			}
		},
        methods:{
            emitParentEvent(){
                this.$emit('someEvent','hello parent,this is child');
            }
        }
	}
</script>

28:组件事件配合v-model使用(场景:组件A中输入,组件B实时接收)

<!--Child-->
<template><!--html内容-->
    <h3>Child</h3>
    <p>child input <input type="text" v-model="msg" @input="emitParentEvent"/></p>
    <p>child output </p>
</template>

<!--js code-->
<script>
	export default {
		data (){
			return {
				msg:""
			}
		},
        methods:{
            emitParentEvent(){
                this.$emit('someEvent1',this.msg);
            }
        },
        watch:{
            msg(newVal,oldVal){
                 this.$emit('someEvent2',this.msg);
            }
        }
	}
</script>
<!--Parent-->
<template><!--html内容-->
    <h3>组件事件</h3>
    <ChildEvent @someEvent1="getChildDataByInput" @someEvent2="getChildDataByWatch"/>
    <p>Here parent(Methods1:input event): </p>
    <p>Here parent(Methods2:watch): </p>
</template>

<!--js code-->
<script setup>
    import ChildEvent from './ChildEvent.vue';
</script>
<script>
	export default {
		data (){
			return {
				msg1:"",
                msg2:""
			}
		},
        methods:{
            getChildDataByInput(data){
                this.msg1 = data;
            },
            getChildDataByWatch(data){
                this.msg2 = data;
            }
        }
	}
</script>

29:组件通过props实现数据子传父传递

<!--Parent-->
<template><!--html内容-->
    <h3>通过Function实现子传父</h3>
    <PropFunChildDemo :fun="fun"></PropFunChildDemo>
    <p>父组件:子组件传参-</p>
</template>

<script setup>
import PropFunChildDemo from './PropFunChildDemo.vue';
</script>
<!--js code-->
<script>
	export default {
		data (){
			return {
				msg:""
			}
		},
        methods:{
            fun(val){
                console.log('子组件传递过来的值:' + val)
                this.msg = val
            }
        },
        computed:{
            
        },
        watch:{

        }
	}
</script>
<!--child-->
<template><!--html内容-->
    <h3>Child组件</h3>
    <p>
        <button @click="childTransParam">传参</button>
    </p>
</template>


<!--js code-->
<script>
	export default {
		data (){
			return {
				msg:"what does child say"
			}
		},
        methods:{
            childTransParam(){
                this.fun(this.msg)
            }
        },
        computed:{
            
        },
        watch:{

        },
        props:{
            fun:Function
        }
	}
</script>

30:透传属性Attributes(实际使用较少)

插槽

官方文档:https://cn.vuejs.org/guide/components/slots.html

31:<slot>基础

组件生命周期’

基础知识

生命周期钩子函数,来控制Vue组件的初始化时机(设置好侦听,编译模板,挂载实例到DOM,数据变化时更新DOM)

官方文档:https://cn.vuejs.org/guide/essentials/lifecycle.html

创建期:beforCreate、created

挂载期:beforeMount、mounted

更新期:beforeUpdate、updated

销毁期:beforeUnmount、unmounted

image

<template>
  <h3></h3>
  <button @click="handleClick">Click me</button>
</template>
<script>
  export default {
    name: 'App',
    beforeCreate() {
      console.log('App beforeCreate');
    },
    created() { 
      console.log('App created');
    }, 
    beforeMount() {
      console.log('App beforeMount');
    },
    mounted() {
      console.log('App mounted');
    },
    beforeUpdate() {
      console.log('App beforeUpdate');
    },
    updated() {
      console.log('App updated');
    },
    beforeUnmount() { 
      console.log('App beforeUnmount');
    },
    unmounted() {
      console.log('App unmounted');
    },
    data() {
      return {
        msg:'Hello Vue3!'
      } 
    },
    methods: {
      handleClick() {
        this.msg += '!';
      },
    },
  };
</script> 

生命周期的应用

动态组件 <component :is="componentName">

关键:不能使用<script setup>​来import组件

<!--App.vue-->
<template>
  <h3></h3>
  <ComponentA />
  <ComponentB />
  <component :is="showComponent"></component>
  <button @click="handleClick">切换组件</button>
</template>
<script>
  import ComponentA from './compnents/ComponentA.vue'
  import ComponentB from './compnents/ComponentB.vue'
  export default {
    data() {
      return {
        msg:'Dynamic Component Example',
        showComponent:"ComponentA"
      } 
    },
    methods: {
      handleClick() {
        this.showComponent = this.showComponent === "ComponentA" ? "ComponentB" : "ComponentA";
      },
    },
    components: {
      ComponentA,
      ComponentB
    }
  };
</script> 
<!--ComponentA-->
<template>
    <h3>componentA</h3>
</template>
<script>
    export default {
        name: 'ComponentA',
                name: 'ComponentB',
        beforeCreate() {
        console.log('ComA beforeCreate');
        },
        created() { 
        console.log('ComA created');
        }, 
        beforeMount() {
        console.log('ComA beforeMount');
        },
        mounted() {
        console.log('ComA mounted');
        },
        beforeUpdate() {
        console.log('ComA beforeUpdate');
        },
        updated() {
        console.log('ComA updated');
        },
        beforeUnmount() { 
        console.log('ComA beforeUnmount');
        },
        unmounted() {
        console.log('ComA unmounted');
        },
        data() {
        return {
            msg:'Hello ComA!'
        } 
        },
    }
</script>   
<!--ComponnetB-->
<template>
    <h3>componentB</h3>
</template>
<script>
    export default {
        name: 'ComponentB',
        beforeCreate() {
        console.log('ComB beforeCreate');
        },
        created() { 
        console.log('ComB created');
        }, 
        beforeMount() {
        console.log('ComB beforeMount');
        },
        mounted() {
        console.log('ComB mounted');
        },
        beforeUpdate() {
        console.log('ComB beforeUpdate');
        },
        updated() {
        console.log('ComB updated');
        },
        beforeUnmount() { 
        console.log('ComB beforeUnmount');
        },
        unmounted() {
        console.log('ComB unmounted');
        },
        data() {
	        return {
	            msg:'Hello ComB!'
	        } 
        },
    }
</script>

保持组件存活<keep-alive>

在console中,能看到

<!--App.vue-->
<script setup>

</script>
<template>
  <h3></h3>
  <ComponentA />
  <ComponentB />
  <KeepAlive>
    <component :is="showComponent"></component>
  </KeepAlive>
  <button @click="handleClick">切换组件</button>
</template>
<script>
  import ComponentA from './compnents/ComponentA.vue'
  import ComponentB from './compnents/ComponentB.vue'
  export default {
    data() {
      return {
        msg:'Dynamic Component Example',
        showComponent:"ComponentA"
      } 
    },
    methods: {
      handleClick() {
        this.showComponent = this.showComponent === "ComponentA" ? "ComponentB" : "ComponentA";
      },
    },
    components: {
      ComponentA,
      ComponentB
    }
  };
</script> 
<!--ComponentA-->
<template>
    <h3>componentA</h3>
    <p></p>
    <button @click="handleClick">切换内容</button>
</template>
<script>
    export default {
        name: 'ComponentA',
                name: 'ComponentB',
        beforeCreate() {
        console.log('ComA beforeCreate');
        },
        created() { 
        console.log('ComA created');
        }, 
        beforeMount() {
        console.log('ComA beforeMount');
        },
        mounted() {
        console.log('ComA mounted');
        },
        beforeUpdate() {
        console.log('ComA beforeUpdate');
        },
        updated() {
        console.log('ComA updated');
        },
        beforeUnmount() { 
        console.log('ComA beforeUnmount');
        },
        unmounted() {
        console.log('ComA unmounted');
        },
        data() {
            return {
                msg:'Hello ComA!'
            } 
        },
        methods: {
            handleClick() {
                this.msg = this.msg === 'Hello ComA!' ? 'Content Changed!' : 'Hello ComA!';
            },
        },
    }
</script>    
<!--ComponnetB-->
<template>
    <h3>componentB</h3>
</template>
<script>
    export default {
        name: 'ComponentB',
        beforeCreate() {
        console.log('ComB beforeCreate');
        },
        created() { 
        console.log('ComB created');
        }, 
        beforeMount() {
        console.log('ComB beforeMount');
        },
        mounted() {
        console.log('ComB mounted');
        },
        beforeUpdate() {
        console.log('ComB beforeUpdate');
        },
        updated() {
        console.log('ComB updated');
        },
        beforeUnmount() { 
        console.log('ComB beforeUnmount');
        },
        unmounted() {
        console.log('ComB unmounted');
        },
        data() {
        return {
            msg:'Hello ComB!'
        } 
        },
    }
</script>

异步组件

官方文档:https://cn.vuejs.org/guide/components/async.html

<!--代码片段-->
<script>
  import { defineAsyncComponent } from 'vue';
  // 异步组件
  const ComponentB = defineAsyncComponent(() =>
    import('./compnents/ComponentB.vue')
  );
  export default {
    data() {
      return {
		
      } 
    },
    components: {
      ComponentB
    }
</script>
<template>
  <h3></h3>
  <KeepAlive>
    <component :is="showComponent"></component>
  </KeepAlive>
  <button @click="handleClick">切换组件</button>
</template>
<script>
  import ComponentA from './compnents/ComponentA.vue'
  import { defineAsyncComponent } from 'vue';
  // 异步组件
  const ComponentB = defineAsyncComponent(() =>
    import('./compnents/ComponentB.vue')
  );
  export default {
    data() {
      return {
        msg:'Dynamic Component Example',
        showComponent:"ComponentA"
      } 
    },
    methods: {
      handleClick() {
        this.showComponent = this.showComponent === "ComponentA" ? "ComponentB" : "ComponentA";
      },
    },
    components: {
      ComponentA,
      ComponentB
    }
  };
</script> 
<!--ComponentA-->
<template>
    <h3>componentA</h3>
    <p></p>
    <button @click="handleClick">切换内容</button>
</template>
<script>
    export default {
        name: 'ComponentA',
        beforeCreate() {
        console.log('ComA beforeCreate');
        },
        created() { 
        console.log('ComA created');
        }, 
        beforeMount() {
        console.log('ComA beforeMount');
        },
        mounted() {
        console.log('ComA mounted');
        },
        beforeUpdate() {
        console.log('ComA beforeUpdate');
        },
        updated() {
        console.log('ComA updated');
        },
        beforeUnmount() { 
        console.log('ComA beforeUnmount');
        },
        unmounted() {
        console.log('ComA unmounted');
        },
        data() {
            return {
                msg:'Hello ComA!'
            } 
        },
        methods: {
            handleClick() {
                this.msg = this.msg === 'Hello ComA!' ? 'Content Changed!' : 'Hello ComA!';
            },
        },
    }
</script>    
<!--ComponnetB-->
<template>
    <h3>componentB</h3>
</template>
<script>
    export default {
        name: 'ComponentB',
        beforeCreate() {
        console.log('ComB beforeCreate');
        },
        created() { 
        console.log('ComB created');
        }, 
        beforeMount() {
        console.log('ComB beforeMount');
        },
        mounted() {
        console.log('ComB mounted');
        },
        beforeUpdate() {
        console.log('ComB beforeUpdate');
        },
        updated() {
        console.log('ComB updated');
        },
        beforeUnmount() { 
        console.log('ComB beforeUnmount');
        },
        unmounted() {
        console.log('ComB unmounted');
        },
        data() {
	        return {
	            msg:'Hello ComB!'
	        } 
        },
    }
</script>

依赖注入(props​逐级透传:provide​、inject

官方文档:https://cn.vuejs.org/guide/components/provide-inject.html

温馨提示:provide和inject只能由上往下传

image

“全局数据”,在main.js

//main.js
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)
app.provide('globalData', 'Provide/Inject in Vue3')
app.mount('#app')

App.vue​中有两种方式,只能二选一,provide()方式更通用

<!--App.vue-->
<template>
  <h3>Root</h3>
  <Parent />
</template>

<script>
  import { provide } from 'vue';
  import Parent from './components/Parent.vue'
  export default {
	//方式一:固定信息
    //provide: {
    //  rootMsg1: "固定信息"
    //},
	//方式二:可以是data里的变量(更通用)
    provide() {
      return {
        rootMsgWay2: this.rootMsg
      }
    },
    data() {
      return {
        rootMsg: 'Hello from Root'
      }
    },
    components: {
      Parent
    }
  }
</script>

Parent.vue

<!--Parent.vue-->
<template>
    <h3>Parent</h3>
    <Child />
</template>

<script>
    import Child from './Child.vue'
    export default {
        name: 'Parent',     
        components: {
            Child
        }
    }   
</script>

Child.vue

<template>
    <h3>Child</h3>
    <p></p>
    <p>Child get:</p>
    <p>Child get:</p>
    <p>Child get:</p>
</template>

<script>
    export default {
        name: 'Child',
        inject: ['globalData', 'rootMsg1', 'rootMsgWay2'],
        data () {
            return {
                childMsg: this.rootMsgWay2
            };
        },
    }
</script>

Vue应用

官方文档:https://cn.vuejs.org/guide/essentials/application.html

每个 Vue 应用都是通过 createApp​ 函数创建一个新的 应用实例

//main.js
import { createApp } from 'vue'
import App from './App.vue'
//App:Vue的实例对象
//在一个Vue项目中,有且只有一个Vue的实例对象
const app = createApp(App)
//App:就是根组件(其他组件都是一层一层往下执行)


//挂载应用
app.mount('#app')

浏览器可执行文件:HTML、CSS、JavaScript、Image

构建工具:Webpack、Vite(Vue使用的)

# vue