vu3----1

242 阅读6分钟

vue3第一天

vue框架(4周)

react 框架(3-4周)

小程序和uniapp

web3.0和vue2 复习

就业周

vue3

官网:https://cn.vuejs.org/
 <div id="box">
        {{str}}
    </div>
    <div id="box2">
        {{str}}
    </div>
    <script>
        let obj ={str:"hello"}
        //创建一个根实例
        let app=Vue.createApp({
            data(){  //data函数的作用向组件或容器提供数据  //Proxy
                return {
                    str:'hello world'   //响应式数据 数据变化了,视图会自动更新(vue会找到变更的差异部分,进行局部的刷新)
                                        //数据驱动  (数据变化了,视图会自动更新)
                }
            }
        }).mount("#box")  //mount挂载,把app和特定的容器进行关联,关联以后,app就可以控制容器渲染的内容
        console.log(app)
        //面试题:data函数要返回一个对象?
        //每一个实例有独立的数据对象互相之间不影响
​
        let app2=Vue.createApp({
            data(){
                return {
                    str:"qf"
                }
            }
        }).mount("#box2")
    </script>

什么是vue

渐进式JavaScript框架  (声明式编程)
易学易用,性能出色,适用场景丰富的 Web 前端框架    vue性能:引入了虚拟demo机制,引入了diff算法,diff算法可以进行差异更新,采用了声明式编程

什么叫渐进式框架

弱主张的框架,只提供必要的和核心的功能,需要时再进行逐渐的扩展

搭建环境

脚手架环境(用命令搭建一个空的vue项目)

在html文件中引入vue.js(cdn)

    <div id="box">
        {{str}}
    </div>
    <script>
        // console.log(Vue.createApp)
        //创建一个根实例
     let app=Vue.createApp({
        data(){  //data函数的作用向组件或者容器提供数据
            return{
                str:'hello word'  //响应式数据(数据变化了,视图也会自动更新)---vue会找到变更的差异部分,进行局部的刷新
                //数据驱动:数据变化了,视图也会自动更新
            }
        }
     }).mount('#box')  //mount挂载,把app和特定的容器进行关联,关联以后,app就可以控制容器渲染的内容
     console.log(app)
​
     //面试题:data函数为什么要返回一个对象?
     //因为每一个实例都有独立的数据对象,它们互相之间不影响
    </script>

差值表达式

{{js表达式}} 是差值表达式 mustache

含有差值表达式的html叫模板(template)

  <div id="box">
        {{str}}  ---  {{str.toUpperCase()}} ---反转  {{str.split("").reverse().join("")}}
    </div>
    <script>
        let appInstance = Vue.createApp({
            data(){
                return {
                    str:"hello world"
                }
            },
            // template:`<div>   //template的优先级比  mount挂载的元素高!
            //                 test hello
            //          </div>
            //     `
        });
        let app = appInstance.mount("#box");
      
    </script>

MVVM

M model 模型    数据
v view  视图    渲染数据
vm viewmodel 视图模型  数据驱动

vue的两大核心是数据驱动和组件系统

指令(directive)

组件(component)

路由(router)

vuex

第三方库

指令

1.v-text 作用和{{差值表达式}}一样

2.v-bind 把变量或数据绑定到对象的属性上 v-bind:属性=“变量" 简写为":" 数据变化视图会变化,视图变化,数据不会变化,所以是一个单向绑定指令

3.v-model 双向绑定指令 (v-bind和v-on的合体)

修饰符

.lazy 文本框失去焦点的时候再帮我们将文本框的值同步给Model
.number 把文本框的数据当成数值处理
.trim 去掉前后空格

4.v-on 指令 可以简写为@ $event 是事件对象

可以响应多个事件对象

<button v-on="{'mouseover':()=>change(1),'mouseout':change.bind(this,-1)}">test</button>

事件处理函数放到methods里

  methods:{
                // increment(){
                //     this.n=this.n+1
                // },
                // sub(){
                //     if(this.n>1){
                //         this.n=this.n-1 
                //     }
                   
                // }
                change(p){
                    console.log("change",p)
                    // if(e.target.innerHTML==="-" && this.n>1){
                    //     this.n--;
                    // }
                    // else if(e.target.innerHTML==="+"){
                    //     this.n++;
                    // }
                  //  this.n=Math.max(this.n+p,1)
                  
                   if(this.n+p>1){
                         this.n=this.n+p;
                   }
                   else{
                    this.n=1
                   }
                }
            }

5.v-if和v-show

区别 v-show 只是切换元素的css样式,可见还是不可见

v-if 惰性指令 true 才渲染 false 不渲染

6.v-for

   <div id="box">
        <ul>
            <li v-for="item in list" :key="item.id">  
                //key是个唯一的值,通过key值能找到对应的同一个节点,判断数据的变化,从而减少比对次数,提高比对效率。
                {{item.name}} {{item.age}}
            </li>
        </ul>
    </div>
    <script>
        const list=Mock.mock({
            "list|30":[{
                id:"@id",
                name:'@cname',
                "age|20-30":25
            }]
        })
        console.log(list)
        let app = Vue.createApp({
            data() {
                return {
                    list:list.list
                }
            }
        }).mount('#box')
        

v-else

v-else-if

vue3第二天

npm i vue -S

绑定样式

绑定style

 v-bind:style="{key:value.....}"
 v-bind:style="[styleObj1,styleObj2.....]"

绑定class

v-bind:class="{className:布尔表达式,。。。。。}"
v-bind:class="[{clasaName:布尔表达式},{   }]"

von修饰符

.stop 阻止冒泡

.capture 捕获模式

.prevent 阻止默认的行为

.once 事件只响应一次

.self 只有本身响应

.enter 回车事件

vfor遍历数字,遍历字符串,对象

    <div id="box">
        <!-- <ul>
            <li v-for="x in str"  :key="x">{{x}}</li>
        </ul> 
        <ul>
            <li v-for="(value,key,index) in obj">
                {{index}}---{{key}}---{{value}}
            </li>
        </ul>-->
        <ul>
            <li v-for="(item,index) in arr" :key="item">
                    {{index}}--{{item}}
            </li>
        </ul>
    </div>

计算属性

<div id="box">
        <span>{{str}}</span>
    </div>
    <script>
        let app = Vue.createApp({
            data() {
                return {
                    str:'海鸥'
                }
            },
            render(){   //vue运行时会把模板转换成render函数
                // console.log(Vue.h)
                return Vue.h("span",{title:'哈哈哈哈'},this.str)
            }
        }).mount("#box")
    </script>
<div id="box">
        <input type="text" v-model="str"> <br>
        {{reverseStr}}
        <button @click="getC">获取计算属性的值</button>
    </div>
    <script>
        let app = Vue.createApp({
​
            //计算属性:值变化了,返回的计算值自动更新(如果数据不变化取缓存(取上一次计算的结果))
            computed:{
                reverseStr(){
                    return this.str.split('').reverse().join('')+Math.random().toFixed(2)
                }
            },
            data() {
                return {
                    str:'hhajsuhdhshaewy'
                }
            },
            methods: {
                getC(){
                    console.log(this.reverseStr)
                }
            },
        }).mount("#box")
    </script>

计算属性 get和set的用法

<div id="box">
        <input type="text" maxlength="20"  v-model="str">
        <button @click="info='海鸥'">点击按钮</button>
        {{info}}
    </div>
    <script>
        let app = Vue.createApp({
            computed:{
                info:{
                    get(){
                        return `还可以输入${20-this.str.length}个字`
                    },
                    set(value){
                        this.str=value
                    }
                }
            },
            data() {
                return {
                    str:""
                }
            },
        }).mount("#box")
    </script>
        /**
         * v-bind  v-model
         * v-if    v-show
         * v-text  v-html
         * v-on    v-for
         * v-memo  v-once
         * v-pre   v-cloak
        */

vue3第三天

组件 component

可以复用的页面的一部分,叫做组件(本质就是一组dom元素的封装)

组件的分类

全局组件:一旦声明可以在任何地方使用

局部注册的组件:需要调用 才能使用

<div id="box">
        <One></One>
        全局(<Local></Local></div>
   
    <script>
        //vnode
        // let div={
        //     tag:"div",
        //     props:{
        //         id:"box"
        //     },
           
        // }
        let Local=Vue.defineComponent({  //定义一个局部注册的组件
            template:`<div>局部注册的组件</div>`
        })
        let appInstance = Vue.createApp({  //全局组件
            components:{  //局部注册的组件,需要在组件里进行里注册,才能在这个组件的模板里使用
                Local
            },
            data() {
                return {

                }
            }
        })
        appInstance.component("Two",{  //全局组件在任何其他组件的模板里都可以使用,不用注册
            template:`<div>two component</div>`
        })
        appInstance.component("One",{
            components:{  //注册组件
                Local
            },
            template:`<div>one component  One( <Local></Local></div>) <Two></Two>`
        })
       let app = appInstance.mount('#box')

      
    </script>

组件component

1.定义

可以复用的页面的一部分,叫组件(本质就是一组dom元素的封装)

2.分类

全局组件

 <div id="box">
        <!-- 不用注册就可以在App的模板里使用 -->
         <Counter></Counter>  
    </div>
    <script>
        let appInstance = Vue.createApp({
            data() {
                return {}
            }
        })
        //定义全局组件Counter
        appInstance.component("Counter",{ 
            template:`
                <div>Counter组件 {{n}}  <button @click="inc">+</button></div>

            `,
            data(){
                return {
                    n:1
                }
            },
            methods:{
                inc(){
                    this.n++
                }
            }
        })
        let app= appInstance.mount('#box')
    </script>

局部注册的组件

组件通讯

1.父传子

<div id="box">
        <!-- 父组件通过自定义属性把值传给子组件 -->
        <box-message money="111"></box-message>
        <button>弹出</button>
    </div>
    <script>
        let boxMessage = {
            props:["money"],    //子组件通过 props接受父组件传过来的值
            template: `<div class='message'></div>`
        }
        let app = Vue.createApp({
            components: {
                boxMessage
            },
            data() {
                return {
                    flag:false //控制对话框的显示和隐藏
                }
            }
        }).mount('#box')
 <div id="box">
        <!-- 父组件通过自定义属性把值传给子组件 没有绑定数据传的任何数据都是字符串,加上绑定可以识别各种数据类型和变量-->
        <box-message v-bind:money="111" :title="title" :flag="flag" :arr="arr" :index="index"></box-message>
      
        <button @click="showBox('添加')">添加</button>
        <ul>
            <li v-for="(item,index) in arr" :key="index">{{item}}   <button @click="showBox('修改',index)">修改</button></li>
        </ul>
    </div>
    <script>
        let boxMessage = {
            props:["money","flag","title","arr","index"],    //子组件通过 props接受父组件传过来的值
            template: `<div class='message' v-show="flag">
                {{index}}
                        <h3>{{title}}</h3>
                        {{money}} {{typeof money}} {{flag}}
                        
                        <input type='text' v-model="str" @keyup.enter="add" v-if="title==='添加'" />
                        <input type='text' v-model="str" @keyup.enter="modify" v-else />
                      </div>`,
            data(){
                return {
                    str:""
                }
            },
            watch:{   //监听数据的变化
                index(newIndex){
                    this.str=this.arr[newIndex];
                }
            },
            methods:{
                add(){
                    this.arr.push(this.str);
                    this.str="";
                    //error  这是错误的做法,父组件传给子组件的基本数据类型的值不能改因为是只读的(单向数据流)
                    //父组组件传给子组件引用数据类型的值是可以改的 ,因为地址没变
                  //  this.flag=false  error
                  this.$parent.flag=false;  //这种方法少用,因为破坏了单向数据流
                },
                modify(){
                    console.log("修改")
                }

            }
                
        }
        let app = Vue.createApp({
            components: {
                boxMessage
            },
            methods:{
                showBox(title,index){
                    this.flag=true; //对话框可见
                    this.title=title
                    this.index=index;
                }
            },
            data() {
                return {
                    index:-1, //要修改元素的下标
                    flag:false, //控制对话框的显示和隐藏
                    title:"添加",
                    arr:['aa','bb']
              
                }
            }
        }).mount('#box')
    </script>

props验证

type:类型

default:默认值

required:是否必须传

validator :自定义验证规则

2.子传父

<div id="box">
		<input1 @txt="jia"></input1>
		<!-- <ul>
			<li v-for="(item,index) in arr" :key="index">
				{{item}}
			</li>
		</ul> -->
		<lii :arr="arr"></lii>
	</div>
	<script>
		let lii={
			props:["arr"],
			template:`
			<ul>
			<li v-for="(item,index) in arr" :key="index">
				{{item}}
			</li>
		</ul>
			`
		}
		let input1 = {
			template: `
			<input type="text" v-model="str" @keyup.enter="send">
			`,
			data(){
				return{
					str:''
				}
			},
			methods: {
				send(){
					this.$emit('txt',this.str);
					this.str=''
				}
			},
		}
		let app = Vue.createApp({
			components: {
				input1,lii
			},
			data() {
				return {
					arr: ['海鸥', '哈哈哈']
				}
			},
			methods:{
				jia(str){
					this.arr.push(str)
				}
			}
		}).mount("#box")
	</script>

3.非父子组件的传值

<div id="box">
		<One></One>
		<Two></Two>
	</div>
	<script>
		let emitter = mitt()  //需要去引入mitt   发布订阅模式】、
		let One = {
			template: `<div>One	<button @click="send"> send </button> </div>`,
			methods: {
				send(){
					emitter.emit('haiou','海鸥')  //emit 向兄弟组件传值
				}
			}
		}
		let Two = {
			template: `<div>Two {{data}}</div>`,
			data(){
				return{
					data:23
				}
			},
			created () {  //生命周期的钩子函数,在实例处理完所有状态的相关的选项后调用
				emitter.on('haiou',(data)=>{  //on  接受兄弟组件传过来的值  data就是其他组件传递过来的值
					this.data=data
				})
			}
		}
		let app = Vue.createApp({
			components: {
				One,Two
			},
			data() {
				return {
				}
			},
		}).mount("#box")
	</script>

4.爷孙组件传值

爷组件
export default {
    components: { Test },
    data(){
      return{
        n:2323
      }
    },
 **** provide(){   
      return {
        n:this.n
      }
    }
}
爷组件(使用computed可以使传的值有响应 爷组件的值改变了 孙子的值也会改变)
<template>
  <div>
<Test></Test>
{{ n }} <button @click="n++">+</button>
  </div>
</template>

<script>
import Test from './components/Test.vue';
  *** import {computed} from 'vue'
  export default {
    components: { Test },
    data(){
      return{
        n:2323
      }
    },
   **** provide(){
      return {
        n:computed(()=>this.n)
      }
    }
}
</script>

<style lang="scss" scoped>

</style>
孙组件
<template>
	<div>
		TestSon {{ n }}
	</div>
</template>

<script>
	export default {
		inject:['n']  ***
	}
</script>

<style lang="scss" scoped>

</style>

watch

监控数据的变化

vue3第四天

Object.values 和 Object.keys

let obj={
			a:1,b:2,c:3
		}
		Object.values(obj) //[1,2,3]   Object.values---将对象的值拿到存在数组里面
		Object.keys(obj)  //['a','b',c]   Object.keys----将对象的键拿到存在数组里面

计数器

<div id="box">
		<!-- <Counter :n="obj.n" @nn="change" name="n"></Counter>
		<Counter :n="obj.m" @nn="change" name="m"></Counter>
		<Counter :n="obj.h" @nn="change" name="h"></Counter> -->
		
		<Counter v-for="(value,key,index) in obj" :n="value" @nn="change" :name="key" :key="key"></Counter>
		{{sum}}
	</div>
	<script>

		let Counter = {
			props: ["n", "name"],
			template: `<div>计数器 {{n}} <button @click="add">+</button> </div>`,
			methods: {
				add() {
					this.$emit('nn', this.n + 1, this.name)
				}
			}
		}
		let app = Vue.createApp({
			computed: {
				sum() {
					// return this.obj.n + this.obj.m + this.obj.h
					return Object.values(this.obj).reduce((a,b)=>a+b)
				}
			},
			components: {
				Counter
			},
			data() {
				return {
					obj: {
						n: 3,
						m: 6,
						h: 7,
						jj:99,
						kk:2
					}

				}
			},
			methods: {
				change(...arges) {
					console.log(arges);
					this.obj[arges[1]] = arges[0]
				},
			}
		}).mount("#box")

	</script>

生命周期的钩子函数

<div id="box">
		<input type="text" id="txt" ref="txt">{{str}}
		<Child ref="child"></Child>
		<button @click="sc">删除</button>
	</div>
	<script>
		// 生命周期的钩子函数 => 在组件的各个生命周期中可以自动调用的函数叫做生命周期的钩子函数
		// 创建阶段 挂载阶段 更新阶段 销毁阶段
		// 1. beforeCreate     实例创建前触发
		// 2. created          实例创建完成,
		// 3. beforeMount      模板渲染前,可以访问数据,模板编译完成,虚拟DOM已经存在   
		// 4. mounted          模板渲染完成,可以拿到DOM节点和数据
		// 5. beforeUpdate     更新前
		// 6. updated          更新完成
		// 7. beforeUnmount   销毁前
		// 8. unmounted       销毁后

		let Child = {
			template: `<div>child</div>`,
			methods: {
				fun() {
					console.log('哈哈哈哈哈')
				}
			},
			//创建的钩子函数
			beforeCreate() {   //不能访问数据
				console.log('child beforeCreate')
			},
			created() {   //可以访问数据
				console.log('child created')
			},

			//挂载的钩子函数
			beforeMount() {  //能拿到数据  但拿不到dom节点
				// console.log('beforeMount',this.str,document.getElementById('txt'))
				console.log('child beforeMount')
			},
			mounted() {   //即能拿到数据  还能拿到dom节点
				// console.log('mounted',this.str,document.getElementById('txt'))
				console.log('child mounted')
			},
		}
		let appIntance = Vue.createApp({
			components: {
				Child
			},
			data() {
				return {
					str: '海鸥'
				}
			},
			//创建的钩子函数
			beforeCreate() {   //不能访问数据
				console.log('app beforeCreate', this.str)
			},
			created() {   //可以访问数据
				console.log('app created', this.str)
			},

			//挂载的钩子函数
			beforeMount() {  //能拿到数据  但拿不到dom节点
				// console.log('beforeMount',this.str,document.getElementById('txt'))
				console.log('app beforeMount', this.str, this.$refs.txt)
			},
			mounted() {   //即能拿到数据  还能拿到dom节点
				// console.log('mounted',this.str,document.getElementById('txt'))
				console.log('app mounted', this.str, this.$refs.txt),
					this.$refs.child.fun()
			},

		
			//更新阶段
			beforeUpdate() {  //更新dom数前
				console.log('app beforeUpdate',this.str)
			},
			updated() {   //更新dom数之后
				console.log('app updated',this.str)
			},	
			
			//销毁阶段
			beforeUnmount() {
				console.log('app beforeUnmount')
			},
			unmounted() {
				console.log('app unmounted')
			},
			methods:{
				sc(){
					appIntance.unmount()
				}
			}
		})
		appIntance.mount("#box")
	</script>

子组件给父组件传值

  1. 监听

    <My-form :index="index" :arr="arr" v-on:evt="changeIndex($event)"></My-form>
    
  2. 发送

     this.$emit("evt",0)  //2.发送是新值给父组件
    
  3. 接收

      changeIndex(n){  //3.接收 在事件处理函数里接收子组件传过来的值n
                        console.log(n)
                        this.index=n;
                    }
    

v-model 双向绑定组件

<组件 v-model="变量" />等价于

<组件 v-bind:modelValue="变量" v-on:update:model-value="变量=$event" />

兄弟组件传值

    <script src="https://unpkg.com/mitt/dist/mitt.umd.js"></script>
      let emitter= mitt();
      let One={
            template:`<div>one compnent <button @click="send">send</button></div>`,
            methods:{
                send(){
                    emitter.emit("msg",12345)  //向兄弟组件传值
                }
            }
        }
        
        let Two={
            template:`<div>Two compnent {{num}}</div>`,
            data(){
                return {
                   num:0 
                }
                
            },
            created(){  //生命周期的钩子函数  在实例处理完所有与状态相关的选项后调用
                emitter.on("msg",(data)=>{  //data就是其他组件传递过来的值
                    this.num=data;
                })
            }   
        }

指令 12

组件

组件定义和使用

组件的传值

生命周期的钩子函数

动态组件

插槽

路由

vuex

第三方库

生命周期的钩子函数

在组件的各个生命周期中可以自动调用的函数叫生命周期的钩子函数

创建阶段

beforeCreate 实例初始化时调用

created 在实例处理完所有与状态相关的选项后调用

挂载阶段

beforeMount 在实例挂载之前调用 可以拿到数据,但是拿不到真实的dom节点

mounted 挂载之后调用 既可以拿到数据,也可以拿到真实的dom节点

ref

    <input  ref="节点标识" /> 
    
    this.$refs.ref节点标识 拿到节点 
    this.$refs.ref节点标识.数据名字  拿到数据

创建和挂载节点父子组件的执行顺序

app beforeCreate undefined
app created hello
app beforeMount hello undefined
child beforeCreate
child created
child beforeMount
child mounted
app mounted

更新阶段

beforeUpdate 状态已经更新后,DOM树更新前调用

updated 状态已经更新后 DOM树更新后调用

销毁阶段

beforeUnmount

组件卸载之前调用 清理资源,防止内存泄露

unmounted

组件卸载之后调用

<div id="box">
		<input type="text" id="txt" ref="txt">{{str}}
		<Child ref="child"></Child>
		<button @click="sc">删除</button>
	</div>
	<script>
		// 生命周期的钩子函数 => 在组件的各个生命周期中可以自动调用的函数叫做生命周期的钩子函数
		// 创建阶段 挂载阶段 更新阶段 销毁阶段
		// 1. beforeCreate     实例创建前触发
		// 2. created          实例创建完成,
		// 3. beforeMount      模板渲染前,可以访问数据,模板编译完成,虚拟DOM已经存在   
		// 4. mounted          模板渲染完成,可以拿到DOM节点和数据
		// 5. beforeUpdate     更新前
		// 6. updated          更新完成
		// 7. beforeUnmount   销毁前
		// 8. unmounted       销毁后

		let Child = {
			template: `<div>child</div>`,
			methods: {
				fun() {
					console.log('哈哈哈哈哈')
				}
			},
			//创建的钩子函数
			beforeCreate() {   //不能访问数据
				console.log('child beforeCreate')
			},
			created() {   //可以访问数据
				console.log('child created')
			},

			//挂载的钩子函数
			beforeMount() {  //能拿到数据  但拿不到dom节点
				// console.log('beforeMount',this.str,document.getElementById('txt'))
				console.log('child beforeMount')
			},
			mounted() {   //即能拿到数据  还能拿到dom节点
				// console.log('mounted',this.str,document.getElementById('txt'))
				console.log('child mounted')
			},
		}
		let appIntance = Vue.createApp({
			components: {
				Child
			},
			data() {
				return {
					str: '海鸥'
				}
			},
			//创建的钩子函数
			beforeCreate() {   //不能访问数据
				console.log('app beforeCreate', this.str)
			},
			created() {   //可以访问数据
				console.log('app created', this.str)
			},

			//挂载的钩子函数
			beforeMount() {  //能拿到数据  但拿不到dom节点
				// console.log('beforeMount',this.str,document.getElementById('txt'))
				console.log('app beforeMount', this.str, this.$refs.txt)
			},
			mounted() {   //即能拿到数据  还能拿到dom节点
				// console.log('mounted',this.str,document.getElementById('txt'))
				console.log('app mounted', this.str, this.$refs.txt),
					this.$refs.child.fun()
			},

		
			//更新阶段
			beforeUpdate() {  //更新dom数前
				console.log('app beforeUpdate',this.str)
			},
			updated() {   //更新dom数之后
				console.log('app updated',this.str)
			},	
			
			//销毁阶段
			beforeUnmount() {
				console.log('app beforeUnmount')
			},
			unmounted() {
				console.log('app unmounted')
			},
			methods:{
				sc(){
					appIntance.unmount()
				}
			}
		})
		appIntance.mount("#box")
	</script>

activated 组件启用缓存的时候调用 deacitvated 组件停用缓存的时候调用

vue3第五天

手动搭建vue3

npm init -y 初始化

npm i vue -S 安装vue

npm i vite -S 打包

npx vite 运行

在package.json文件夹中更改运行命令

 "scripts": {

  "test": "echo "Error: no test specified" && exit 1",

  "dev":"npx vite"  //dev 这个单词可以随便起 

 },
 
 运行方式:npm run dev   等价于 npx vite

npx vite build 打包项目

"scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "dev": "npx vite",
    "build":"npx vite build"    //build这个单词可以随便起 
  },
  运行方式:npm run build 等价于 npx vite build

html

<div id="box">
	
	</div>
	<script src="./js/vue.js" type="module"></script>

js

import {createApp,h} from 'vue'
let app = createApp({
	render(){
		return h('span',null,this.yy)  //span标签  null属性  yy内容 
	},
	data() {
		return {
			yy: '海鸥'
		}
	},
}).mount("#box")

自动搭建vue3

npm init -y 初始化

npm init vue@latest 搭建脚手架

npm i sass -S 写样式 不报错

npm i normalize.css 重置css的样式

<template>
  <div>
    <p>哈哈哈</p>
    <div class="item">app</div>
    <div class="item">海鸥</div>
  </div>
</template>

<script>
export default {

};
</script>

<style lang="scss" scoped>    //scoped  只对当前的组件有作用
div{
  p{
    color: blue;
    &:hover{     //上一级
      color: aqua;
    }
  }
  background-color: red;
  .item{
    color: green;
  }
}
</style>

动态组件

根据组件的名字来渲染组件的内容

<Keep-alive></Keep-alive>   //用来包裹 <component></component> 组件 可以保存组件的内容  

activated   组件启用缓存的时候调用
deacitvated  组件停用缓存的时候调用

  <keep-alive :include="['One']">   //给one和two组件写一个name:对应的名字  然后在keep-alive中操作,写了one这样就只保存one 中的数据
      <component :is="cname"></component>
    </keep-alive>

cname

<template>
  <div>
    动态组件
	<keep-alive>
	 <component :is="cname"></component>
	</keep-alive>
  
   <button @click="cname='One'">one</button>
   <button @click="cname='Two'">two</button>
  </div>
</template>

<script>
import One from "./One.vue";
import Two from "./Two.vue";
export default {
  components: { One, Two },
  data(){
	return{
		cname:'One'
	}
  },
};
</script>

<style lang="scss" scoped></style>

插槽(slot)

组件的预留位置可以在不修改组件代码的前提下,扩展组件的内容

匿名插槽

Demo.vue

<template>
  <div>
	<slot></slot> <input type="text">
	Demo组件
  </div>
</template>

<script>
export default {

};
</script>

<style lang="scss" scoped></style>

app.vue

<template>
  <div>
<Demo>
  <template v-slot:default>    //  使用v-slot绑定插槽 ,default 表示没有名字的插槽 ----匿名插槽
     <span>用户名:</span>
  </template>
</Demo>
  </div>
</template>

<script>
import Demo from './components/Demo.vue'
  export default {
    components:{
      Demo
    }
  }
</script>

<style lang="scss" scoped>

</style>

有名字的插槽----具名插槽

<slot name="btn"></slot>

<template v-slot:btn>
   <button>添加</button>
  </template>

v-slot: 可以简写为

通过插槽传值 ----作用域插槽

<slot name="btn" :n="5"></slot>

 <template v-slot:btn="props" >   //props 这个名字不定
   <button>添加 {{ props.n }}</button>
  </template>

添加

  add() {
      if (!this.newsTitle || !this.content) {
        return alert("请输入完整数据");
      }
      this.list.push({
        id: Date.now(),
        title: this.newsTitle,
        content: this.content,
      });
      this.close();
    },

删除

	remove(id){
		let index=this.list.findIndex(item=>item.id===id);
		// console.log(index)
		this.list.splice(index,1)
	}

修改

 editOk() {
      let index = this.list.findIndex((item) => item.id === this.id);
      this.list[index].title = this.newsTitle;
      this.list[index].content = this.content;
      this.close();
    },

搜索

computed:{
	filterList(){
		return this.list.filter(item=>item.title.includes(this.kw))
	}
  },

vue3第六天

watch的使用

<template>
	<div>
demo{{ n }} <button @click="n++">+</button>
{{ obj }}
<button @click="obj.a++">+</button>
	</div>
</template>

<script>
	export default {
		data(){
			return{
				n:5,
				obj:{
					a:1
				}
			}
		},
		
		// watch:{
		// 	n(newV,oldV){
		// 		console.log(newV,oldV)
		// 	}
		// }
		
		watch:{
			n:{   //监听普通数据
				handler(newV,oldV){
					console.log(newV,oldV)
				}
			},
			obj:{   //监听对象
				handler(newV){
					console.log(newV)
				},
				deep:true, //对象要用深度监听,否则监听不到
				immediate:true  //立即监听
			}
		}
	}
</script>

<style lang="scss" scoped>

</style>

npm i swiper@5 -S 下载轮播图插件

npm i axios -S 下载axios

nextTick

是一个事件循环中的异步队列中的微任务

this.$nextTick 延迟执行回调,直到dom加载完毕

 <ul>
		<li v-for="(item,index) in list" :key="index" ref="lii">
		{{ item }}
		</li>
	</ul>
	
 
 methods:{
	add(){
		this.list.push(23);
		this.$nextTick(()=>{
			console.log(this.$refs.lii)
		})
	}
  }

组件异步传值

     <TestSwiper :imgs="imgs" v-if="imgs.length>0"></TestSwiper>

跨域设置

代理跨域

vite.config.js
server: {
    proxy: {
      "/api": {
        target: "http://121.89.205.189:3000",
        changeOrigin: true,
      },
    },
  },

 axios.get("/api/banner/list")

vue3第七天

vue3中 v-if的优先级比v-for的优先级高

watch跟computed的区别 (面试题)

1、功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。

2、是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。

3、是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。

4、computed默认第一次加载的时候就开始监听;watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true)

5、使用场景:computed----当一个属性受多个属性影响的时候,使用computed-----购物车商品结算。watch–当一条数据影响多条数据的时候,使用watch-----搜索框.

路由

根据不同的url渲染不同的组件

路由有两种模式

hash模式 #

history模式

路由的重定向和路由的别名

import {createRouter,createWebHistory} from 'vue-router'
import Home from '@/views/Home.vue'
const router = createRouter({
	// 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
	history:createWebHistory(),
	routes:[
		{
			path:'/',
			// redirect: "/home"   //路由的重定向  方法1
			// redirect:{         //方法2
			// 	name:'home'
			// },
			redirect:'/h'    //方法3
		},
	  {          //Route对象
		  path:'/home',
		  name:'home',  //命名路由   对应方法2
		  alias:"/h", //别名     对应方法3
		  component:Home
  
	  },
	  {
		  path:'/two',
		  // component:Two
		  component:()=>import('@/views/Two.vue')
	  }
	] 
  });
  export default router

配置404页面

<template>
  <div>
    app
    <router-link to="/"> 首页</router-link>
    <router-link to="/two">第二页</router-link>
    <router-link to="/xxx">xxx</router-link>
    <RouterView msg="我是HelloWorld组件"></RouterView>
  </div>
</template>

<script>
export default {};
</script>

<style lang="scss" scoped>
.router-link-active{
  color: red;
}
</style>

使用页面只显示404页面方法1

<template>
  <div>
   //使用一个div 将这三个组件包起来
    <div v-show="flag">
      <router-link to="/"> 首页</router-link>
      <router-link to="/two">第二页</router-link>
      <router-link to="/xxx">xxx</router-link>
    </div>

    <RouterView msg="我是HelloWorld组件"></RouterView>
  </div>
</template>

<script>
export default {
  data() {
    return {
      flag: true,   //为true 导航条可见  为false导航条不可见
    };
  },
  //方法1  使用watch监听
  watch: {
    $route: {
      handler(n) {
        this.flag = !n.meta.visible;
      },
      deep: true,
      immediate: true,
    },
  },
};
</script>

<style lang="scss" scoped>
.router-link-active {
  color: red;
}
</style>

使用页面只显示404页面方法2

<template>
  <div>
  //使用一个div 将这三个组件包起来  然后使用 v-show="!$route.meta.visible"  点击的时候xxx的时候只显示404页面
    <div v-show="!$route.meta.visible">
      <router-link to="/"> 首页</router-link>
      <router-link to="/two">第二页</router-link>
      <router-link to="/xxx">xxx</router-link>
    </div>

    <RouterView msg="我是HelloWorld组件"></RouterView>
  </div>
</template>

<script>
export default {};
</script>

<style lang="scss" scoped>
.router-link-active {
  color: red;
}
</style>

配置404页面 在路由上操作的重要代码

{
		path:"/:pathMatch(.*)",
		component:()=>import("@/views/NotFound.vue"),
		meta:{    //路由对象的元信息
			visible:true    //true表示导航条是不可见的
		}
	  }

动态组件

可以缓存

include 决定缓存哪个组件

<KeepAlive :include="['One']">
       <component :is="cname"></component>
      </KeepAlive>

路由

根据不同的url渲染不同的组件

vue-router 4

路由有两种模式

hash # location.hash onhashchange createWebHashHistory()

history模式 createWebHistory()

components 小组件 views 页面的组件

使用步骤

  1. npm i vue-router -S

  2. 引入 import {createRouter,createWebHashHistory} from 'vue-router'

  3. 创建实例

    const router = createRouter({
        // 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
        history: createWebHashHistory(),  //hash模式
        routes:[] 
      })
    
  4. 使用路由插件

    app.use(router)
    

5.组件里就可以使用 RouterLInk 和 RouterView 组件里

路由相关的样式

.router-link-active   对当前 routerLInk  组件有效,也对嵌套路由里的  routerlink 有效
.router-link-exact-active   只对当前 routerLInk  组件有效,对嵌套路由里的  routerlink  无效

异步组件

切换到这个组件的时候才进行加载,起到一个路由级别的代码分割的作用

   {
            path:"/two",
            component:()=>import("@/views/Two.vue")
        }

重定向命名路由别名

 {
            path:"/",
            // redirect:"/home"  //路由的重定向
            // redirect:{
            //     name:'home'
            // }
            redirect:"/h"
  },
 {       //Route对象
            path:"/home",
            name:"home",  //命名路由
            alias:'/h',  //别名
            component:Home
  },

404页面

{
            path:"/:pathMatch(.*)",
            component:()=>import("@/views/NotFound.vue")
 }

meta

 meta:{   //元信息
              visible:true  //true 表示导航条不可见的
 }
 
     <div class="nav" v-show="!$route.meta.visible">
      <RouterLink to="/home">首页</RouterLink>
      <RouterLink to="/two">第二页</RouterLink>
      <RouterLink to="/xxx">xxx</RouterLink>
    </div>

vue3第八天

vue移动端适配

  • 安装 cnpm i amfe-flexible postcss-pxtorem -S

-安装 npm i normalize.css 重置css的样式

  • amfe-flexible 用于设置根字体大小的

  • postcss-pxtorem 用来自动转换单位的

  • 在根目录创建一个 .postcssrc.js

module.exports = { plugins: { "postcss-pxtorem": { rootValue: 37.5, propList: ["*"], }, }, };

main.js

一定要在main.js里面引入这两个文件
import 'normalize.css'
import  "amfe-flexible"

用自己手机检测移动端的适配

在vite.config.js中写下面的代码,用电脑给手机开热点,然后重启项目 ,会出现一个地址,用手机输入地址

server:{
    host:'0.0.0.0'
  },

代理跨域

必须安装 npm i axios -S

vite.config.js 方法1

 server:{
    host:'0.0.0.0',
    proxy:{
      "/api":{
        "target":"http://47.94.148.165:3001",
        "changeOrigin":true,
        
      }
    }
  },

vite.config.js 方法2

server:{
    host:'0.0.0.0',
    proxy:{
      "/hg":{       //如果使用hg 那么需要使用rewrite把默认的hg去掉
        "target":"http://47.94.148.165:3001",
        "changeOrigin":true,
        
        rewrite: (path) => path.replace(/^/hg/, ''),
      }
    }
  },

App.vue

<script>
import axios from 'axios'
  export default {
    mounted(){
      axios.get('/hg/api/pro/list? count=1').then((res)=>{
        console.log(res)
      })
    }
  }
</script>

放静态资源的

public 打包时不参与

assets 打包时参与

子路由

在components写一个文件夹用于存放对应路由的子路由,下面是子路由的写法

  {
      path: "/my",
      name: "my",
      component: () => import("../views/My.vue"),
      children: [
        {
          path: "tou",
          component: () => import("../components/my/tou.vue"),
        },
        {
          path: "xinx",
          component: () => import("../components/my/xinx.vue"),
        },
      ],
    },

子路由在父路由的写法

 <div>
    <router-link to="/my/tou">头像</router-link>
    <router-link to="/my/xinx">信息</router-link>
	<router-view></router-view>
  </div>

router 和router 的区别

route 路由的对象 身上都是方法

router vue router的实例 身上都是属性

编程式导航

  <button @click="go('/cart')">购物车</button>
  methods:{
    go(path){
      this.$router.push(path)
    }
  }

go

back

forward

push

replace

路由传值

1.动态路由

 //路由传值方法1---动态路由传值
    {
      path:"/detail/:id",
      component:()=>import('../views/Detail.vue')
    },
    
    	<!-- //路由传值方法1---动态路由传值 -->
    <ul>
      <li v-for="(item, index) in list" :key="item.proid" class="row" @click="$router.push(`/detail/${item.proid}`)">
        <div class="item">
          <img :src="item.img1" alt="" />
          <h3>{{ item.proname }}</h3>
        </div>
      </li>
    </ul>
    
       //路由传值方法1---动态路由传值
  mounted() {
    axios.get(`/api/pro/detail/${this.$route.params.id}`).then((res) => {
      console.log(res.data);
      if (res.data.code == "200") {
        this.deatilObj = res.data.data;
      }
    });
  },

2.查询字符串传值

//路由传值方法1---查询字符串传值
    {
      path:"/xq",
      component:()=>import('../views/Detail.vue')
    },
    
    <!-- //路由传值方法1---查询字符串传值 -->
	<ul>
      <li v-for="(item, index) in list" :key="item.proid" class="row" @click="$router.push(`/xq?id=${item.proid}`)">
        <div class="item">
          <img :src="item.img1" alt="" />
          <h3>{{ item.proname }}</h3>
        </div>
      </li>
    </ul>
    
    //路由传值方法1---查询字符串传值
mounted() {
    axios.get(`/api/pro/detail/${this.$route.query.id}`).then((res) => {
      console.log(res.data);
      if (res.data.code == "200") {
        this.deatilObj = res.data.data;
      }
    });
  },