vue3.x 核心语法 , vue3.x + vueRouter+vuex

创建vue3.0项目

yarn global add @vue/cli 安装脚手架版本必须大于4.5.0

升级脚手架

yarn global upgrade @vue/cli

项目2.x版本升级3.x版本

Vue add vue-next

使用vite创建新的3.x项目

1- npm init vite-app 项目名称

2- 进入项目文件,进行依赖安装 yarn

3- 启动项目yarn dev

注意:只挂载的实例,其他都没有 、 多个根标签报错是因为eslint问题,升级eslint即可

composition API

setup

  • setup是composition API 的入口,没有this
  • 执行时间在beforeCreate之前,比所有的生命周期都早
  • 需要有返回值(对象),返回值才可以在模板中使用,但是不是响应式的
 setup() {
    const car = { //只是一个普通对象,数据不是响应式的
      brand: "宝马",
    };
    return { car };
  },
setup的参数
  • context:上下文对象,可以通过es6语法解构setup(props, {attrs, slots, emit})

    • attrs: 获取当前组件标签上所有没有通过props接收的属性的对象, 相当于 this.$attrs
    • slots: 包含所有传入的插槽内容的对象, 相当于this.$slots
    • emit: 用来分发自定义事件的函数, 相当于 this.$emit
<template>
  <div>
    <div>son组件--{{ sonPrice }}--{{ car }}</div>
    <button @click="changeColor">改颜色</button>
    <hr />
    <Sun></Sun>
  </div>
</template>

<script>
import { inject } from "vue";
import Sun from "./Sun.vue";
export default {
  components: { Sun },
  props: ["car"],
  setup(props, context) { 
    // props 获取组建中定义的props
    // context-->用于提交事件emit 等
    console.log(props);
    const sonPrice = inject("price");
    const changeColor = () => {
      context.emit("changeColor", "yellow");
     //-->2.x:this.$emit('changeColor','yellow')
    };
    return {
      sonPrice,
      changeColor,
    };
  },
};
</script>

reactive

  • 接受一个普通对象(复杂类型),返回一个代理对象,实现数据响应式变化
<button @click="car.brand = '奔驰'">修改</button>
//
import { reactive } from "vue";//1-先引入reactive
export default {
  setup() {
    const car = reactive({//2-接受一个普通对象,返回一个代理对象
      brand: "宝马",
    });
    return { car };
  },
};

ref

  • 接受一个简单数据类型,返回一个响应式的对象

    • 也可以接受一个复杂类型,当接受的是复杂类型时,内部会自动调用reactive
  • 这个响应式对象只有一个属性---->value

  • 在script中要使用xxx.value,但是在模板中直接使用xxx,会直接解套,不需要xxx.value

<template>
  <div>
    <div>{{ car.brand }}</div>
    <button @click="car.brand = '奔驰'">修改</button>
    <div>money--{{ money }}</div> //5-在模板中不需要使用value属性
    <div> 名字:{{zs.name}}</div>  ref接受复杂类型
    <button @click="zs.age++">{{zs.age}}</button> ref接受复杂类型
  </div>
</template>

<script>
import { reactive, ref } from "vue";//1- 引入ref这个函数
export default {
  setup() {
    const money = ref(100); //2-接受一个简单数据类型
    console.log(money.value++); //3-js中要使用value这个属性
      const zs = ref({   接受复杂类型,内部实质是调用了reactive
          name:'xiaoming',
          age:18
      })
    const car = reactive({
      brand: "宝马",
    });
    return { car, money,zs };//4-依旧需要return出去
  },
};
</script>

toRefs

  • 把一个响应式对象变成普通对象,但是变化后的对象都是一个ref是响应式的
  • 常规写法,将所有的数据放到state中,在使用toRefs展开运算符return
<template>
  <div>
    <div>{{ car.brand }}</div>
    <button @click="car.brand = '奔驰'">修改</button>
    <div>money--{{ money }}</div>
    <button @click="money++">加钱</button>
  </div>
</template>

<script>
import { reactive, toRefs } from "vue";//1-导入toRefs
export default {
  setup() {
    const state = reactive({ //2-将所有的数据都放在一起
      money: 100,
      car: {
        brand: "宝马",
      },
    });
    return {
      ...toRefs(state), //3- toRefs包裹state,再展开
    };
  },
};
</script>

readonly

  • 只读---->不希望被人修改 —>用于不希望子组件修改父组件的值
<template>
  <div>
    <div>{{ car.brand }}</div>
    <button @click="car.brand = '奔驰'">修改</button>
    <div>money--{{ money }}</div>
    <button @click="money++">加钱</button>
  </div>
</template>

<script>
import { reactive, toRefs,ref, readonly } from "vue";//1-导入readonly
export default {
  setup() {
    const money = ref(100)
    const state = readonly({ // 使用readonly包裹不允许修改的数据
      car: {
        brand: "宝马",
      },
    });
    return {
      ...toRefs(state),
      money:readonly(money) //也可以在这里包裹
    };
  },
};
</script>

computed

  • 计算属性 两种写法

1- 只写一个函数,得到的是一个只读的计算属性

2- 对象形式,get函数是的得到的额属性,set是设置的,实现数据响应式变化

<template>
  <div>今年的年龄:<input type="text" v-model="age" /></div>
  <div>明年的年龄:<input type="text" v-model="nextAge" /></div>
  <div>后年的年龄:<input type="text" v-model="nextAge2" /></div>
</template>

<script>
import { ref, computed } from "vue";//先导入computed
export default {
  setup() {
    const age = ref(18);
    //1-传入一个函数getter,得到一个不允许修改的计算属性
    const nextAge = computed(() => {
      return +age.value + 1;
    });
    //2-传入一个对象,包括get和set,可以创建一个允许修改的计算属性
    const nextAge2 = computed({
      get() {
        return +age.value + 2;
      },
      set(value) {
        age.value = value - 2;
      },
    });
    return { age, nextAge, nextAge2 };
  },
};
</script>

watch

  • 侦听器
<template>
  <div>年龄:<input type="text" v-model="age" /></div>
  <div>钱: <input type="text" v-model="money" /></div>
  <div>车:{{ car.brand }}</div>
  <button @click="car.brand = '奔驰'">改车名</button>
</template>

<script>
import { ref, computed, toRefs, reactive, watch } from "vue"; //1-先引入watch
export default {
  setup() {
    const age = ref(18);
    const state = reactive({
      money: 100,
      car: {
        brand: "宝马",
      },
    });
    /* 
    watch可以有三个参数
    参数1: 监听简单数据类型时,直接写属性名
            监听复杂数据类型时,写成函数形式,返回值必须是监听的属性名
    参数2:监听的属性发送变化时触发的函数
    参数3:额外配置,监听对象的属性时 { deep:true , immediate:false },
    deep:深度监听,immediate: true-->页面一开始就监听,false-->值变了才监听
    */
    watch(
        age, //监听简单数据类型
        (value, oldvalue) => {
      console.log(`age变化了${value}---${oldvalue}`);
    }
    );
    watch(
      () => state.money, //监听复杂数据类型
      (value, oldvalue) => {
        console.log(`state.money变化了${value}--${oldvalue}`);
      }
    );
    watch(
      () => state.car.brand,
      (value, oldvalue) => {
        console.log(`state.car变化了${value}--${oldvalue}`);
      },
      { // 复杂类型内部对象的属性
        deep: true,
        immediate: false,
      }
    );
    //监听整个state,因为是reactive元素,所以监听state不需要写函数形式
    watch(
      state,
      (value)=>{
		console.log(`state变化了--${value}`)
       }
      )
    return { ...toRefs(state), age };
  },
};
</script>

生命周期

  • setup (将2.x版本中beforeCreate和created)
  • onBeforeMount
  • onMounted
  • onBeforeUpdate
  • onUpdated
  • onBeforeUnmount
  • onUnmounted

所有的钩子函数都在setup里面写

onMounted(()=>{
    。。。
})
//写法都是回调函数的形式

组件通信

使用emit通信(父子组件通信)

//父组件中
<Son :price='price' @changePrice='changePrice' ></Son> // 4 - 注册同样的事件
<script>
    import { provide, reactive, readonly, ref, toRefs } from "vue";
    export default {
        setup(){
            let price = ref(999);
            const changePrice =(val)=>{ 
                price.value = val //5- 拿到传来的值.....
            }
            returun{ price,changePrice }
        }
    }
</script>
//Son组件中
  <div>{{price}}</div>
<button @click="changePrice">改值</button>
<script>
    import { provide, reactive, readonly, ref, toRefs } from "vue";
    export default {
        emits:{  // 3--->校验
            changePrice:()=>{
                // 检验逻辑 --返回值是布尔值
                return true / flase 
            },
            changeFn:null//--->不需要校验则为null
        }
        props:['price']
        setup(props,context){ //1-提供 context
           const changePrice=()=>{
               context.emit('changePrice',123) //2-提交emit事件
           }
            returun{ changePrice }
        }
    }
</script>

$attrs 通信 (爷孙组件通信)

  • 与2.x 不一样的地方是,中间组件不再需要注册 v-on:$listeners , 其他基本不变
//父组件中载入子组件
<Son :attrsValue="attrsValue" @changeAttrsValue="changeAttrsValue"></Son>
<script>
    setup(){
        let propsValues = reactive({
            attrsValue: {
                attrsVal: "attrsVal",  
            },
        });
        const changeAttrsValue = (val) => {
            console.log(val);
        };
        return(){
            ...toRefs(propsValues),
            changeAttrsValue
        }
    }
</script>

//子组件中载入孙组件
//在中中间组价添加 $attrs ,作为中间站
<Sun v-bind="$attrs" @changeAttrsValue="changeAttrsValue"></Sun>
<script>
import Sun from "./Sun.vue";
export default {
  components: { Sun },
 // props: ["attrsValue"],  若在子组件中接受的父组件传来的props,则在孙组件中将接收不到了   
  setup(props, context) {
    const changeAttrsValue = (val) => {
      console.log(val);
    };
    return {
      changeAttrsValue,
    };
  },
};
</script>

//孙组件
<template>
  <div>
    孙组件--{{ attrsValue }}
    <button @click="changeAttrsValue">改attrsValue</button>
  </div>
</template>

<script>
export default {
  props: ["attrsValue"],
  setup(props, context) {
    console.log("attrsValue", props);
    const changeAttrsValue = () => {
      context.emit("changeAttrsValue", "changeAttrsValue--->");
        //触发子传父的事件,不论父组件还是子组件中注册了接受的事件,都将可以接受到传来的值
    };
    return {
      changeAttrsValue,
    };
  },
};
</script>

依赖注入 -->跨组件通信/provide与inject

provide与inject

  • 从父组件中提供数据 -->provide
  • 在子(后代)组件中接受----->injecte
//父组件
<template>
  <div>
    <div>价钱:{{ price }}</div>
    <button @click="price++">加钱</button>
    <Demo></Demo>
  </div>
</template>

<script>
import Demo from "./Demo1.vue";
import { ref, provide } from "vue"; //1-先引入provide
export default {
  components: { Demo }, //注册组件
  setup() {
    const price = ref(111);
  	const changeMoney = () => {
      price.value = parseInt(price.value) + 10;
    };
      
    provide("price", price); // 2---提供数据
    provide("changeMoney", changeMoney);  //3----也可以提供方法 
    return {  
        	price , 
           changeMoney
           };
  },
};
</script>

//子组件 Demo1.vue
<template>
  <div>我是demo组件_{{ price }}</div>
  <button @click="changeMoney">demo的按钮</button>
  <Sun></Sun>
</template>

<script>
import Sun from "./Sun.vue";
import { inject } from "vue";//1-先引入inject
export default {
  components: { Sun }, //注册组件
  setup() {
    const price = inject('price'); //获取数据
    const changeMoney = inject("changeMoney");//获取方法
    return {
      price,
     changeMoney
    };
  },
};
</script>
//孙组件 Sun.vue
<template>
  <div>我是孙组件_{{ price }}</div>
  <button @click="changeMoney">demo的按钮</button>
  <Sun></Sun>
</template>

<script>
import { inject } from "vue";//1-先引入inject
export default {
  components: { Sun }, //注册组件
  setup() {
    const price = inject('price'); //获取数据
    const changeMoney = inject("changeMoney");//获取方法
    return {
      price,
     changeMoney
    };
  },
};
</script>

跨组件通讯mitt.js / 兄弟组件通信—>eventBus

  • 跨组件通讯mitt.js ----->vue2.x/ 兄弟组件通信—>eventBus

  • 装包npm i mitt -s

  • 创建文件mitt.js

//mitt.js//1-创建文件
import mitt from 'mitt'
const emitter = mitt();

export default emitter;
  • 兄弟组件1
<template>
  <div>
    我是子组件2
  </div>
  <button @click='changeMsg'>点击修改msg</button>
</template>

<script>
import { ref } from 'vue'
import emitter from '../mitt' //2--需要用到的组件引入

export default {
  name: '',

  setup() {
    const changeMsg = () => {
      emitter.emit('change-msg','123')//3-发布事件,需要传递的值
    }
    return {
      changeMsg,
    }
  },
}
</script>
  • 兄弟组件2
<template>
  <div>
    我是子组件1
    <h1>{{msg}}</h1>
  </div>
</template>

<script>
import { ref, onUnmounted } from 'vue'
import emitter from '../mitt'
export default {
  name: '',

  setup() {
    //初始化
    const msg = ref('hello')
    const changeMsg = (val) => {
    console.log(val) //  '123'    //---使用接收到的参数
    }
    // 监听事件,更新数据
    emitter.on('change-msg', changeMsg) // 4---在接受的组件进行事件监听
    // 显式卸载
    onUnmounted(() => {
      emitter.off('change-msg', changeMsg)//5--在组件销毁钩子函数中进行事件解绑
    })
    return {
      msg,
      changeMsg,
    }
  },
}
</script>

vue3.x配合vuex

博客

  • 安装vuex

    yarn add vuex@next

  • 创建store-----语法跟2.x配合vuex一样

//多模块
import login from './login.js'

import { createStore } from 'vuex' //1-引入createStore
const state = {
  storeValue: {
    name: 'zs11',
    age: 18,
  },
}
const getters = {
  gettersName: (state) => state.storeValue.name,
}
const mutations = {
  updateValName: (state, data) => {
    console.log(data)
    state.storeValue.name = data
  },
  updateValAge(state, data) {
    state.storeValue.age = state.storeValue.age + data
  },
}
const actions = {
  asyncChangeAge(context, data) {
    context.commit('updateValAge', data)
  },
}

export default createStore({
  state,
  getters,
  actions,
  mutations:{login}
})


//login.js
const state = {
  loginState: 'login模块',
}
const mutations = {
  setLoginState(state, data) {
    console.log(data)
    state.loginState = data
  },
}
export default {
  namespaced: true, //2-私有空间
  state,
  mutations,
}
  • 在main.js注册引入创建好的store进行注册
//main.js
import { createApp } from 'vue'
import App from './App.vue'
import store from './store/index.js' //1-引入store
import './index.css'

createApp(App).use(store).mount('#app') //2- .use(store)  进行注册store

  • 在组件中使用----->只有得到store的写法与2.x略有区别,使用store的写法基本一样
<script>
import { useStore } from "vuex"; //1-引入store
import { computed, provide, reactive, readonly, ref, toRefs } from "vue";
export default {
  setup() {
    const store = useStore(); //2-得到store
    const storeVal = computed(() => {
      return store.state.storeValue; // 3- 使用主store的state
    });
    const gettersName = computed(() => {
      return store.getters.gettersName; // 4- 使用主store的getters
    });
    const changeGetters=()=>{
      store.commit('updateValName','修改后值')  // 5- 使用主store的mutations的方法
    }
    const asyncChangeAge=()=>{
      store.dispatch('asyncChangeAge',10)  // 6- 使用主store的actions的方法
    }
    const loginVal =computed(()=>{
      return store.state.login.loginState   // 7- 使用主login模块的state
    })
    const setLoginState=()=>{
      console.log(store);
      store.commit('login/setLoginState','xxxx')  // 8- 使用主login模块的mutations的方法
    }
    return {
      storeVal,
      gettersName,
      changeGetters,
      asyncChangeAge,
      loginVal,
      setLoginState
    };
  },
};

模板refs–获取dom元素,进而操作dom

<template>
  <div>
    <h1 ref="hRef">钩子呢函数</h1>  // 3-指定ref
    <Demo ref="dRef"></Demo>
  </div>
</template>

<script>
import Demo from "./Demo1.vue";
import { ref, provide, onMounted } from "vue"; //1-先引入ref
export default {
  components: { Demo },
  setup() {
  const hRef = ref(null)//2- 初始化ref
  const dRef = ref(null)
  onMounted(()=>{
    console.log(hRef.value); // 3- 操作ref元素
    console.log(dRef.value.changeMoney());//可以拿到子组件中的方法进行调用
  })
    const changeMoney = () => {
      console.log("执行了");
      price.value = parseInt(price.value) + 10;
      console.log(price.value);
    };
    provide("changeMoney", changeMoney);
      
    return { hRef,dRef };
  },
};
</script>

vue3.x路由

  • 安装 npm install vue-router@4
  • 初始化router
  • 2.x 的路径@ ------>3.x–> /src/view/Ids.vue ,可以写/src代表 @
import { createRouter, 
        createWebHistory ,//history模式
        createWebHashHistory //hash模式
       } from 'vue-router' //  1-引包

import { defineAsyncComponent } from "vue"; // 路由的懒加载--->性能优化,优化首屏加载速度
import Login from '/src/view/Login.vue'
import My from '/src/view/My.vue'
import Son from '/src/view/Son.vue'
import Sun from '/src/view/Sun.vue'
const routes = [
  { path: '', redirect: { path: '/login' } }, //重定向路由
  { path: '/login', component: Login },
  {
    path: '/my',
    component: My,
    children: [				//嵌套子路由
      { path: '/my', component: Son },
      { path: '/my/sun', component: Sun },
    ],
  },
  { path: '/ids/:id', 
   component:defineAsyncComponent(  //动态路由-->组件经过懒加载
       ()=> import('/src/view/Ids.vue')
   ) 
  },
]
export default createRouter({
  history: createWebHistory(),//---->history模式----->路径不带#
  history:createWebHashHistory(),//---->hash模式---->路径带#--->具体哪种看项目需要
  routes,   // !!!!---->  此处必须为routes
})
  • 挂载
//main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index' //1-引入
import './index.css'

createApp(App).use(router).mount('#app') // 2-use(router)

  • 页面中使用
<template>
  <div>login页面</div>
  <button @click="goMy">去My</button>
  // 模板中使用路由与2.x语法完全一样, 例如:$route.params.id
</template>

<script>
import { useRoute, useRouter } from "vue-router"; //1-引包
export default {
  setup() {
    const router = useRouter();//----->类比this.$router,使用方法相同
    const route = useRoute();//------->类比this.$route ,使用方法相同
    console.log(route.path);
    const goMy = () => {
      router.push({
        path: "/my",    //---->跳路由
        query: {        //---->传递参数     
          name: "zs",
          age: 18,
        },
      });
        const goIds = () => {
            router.push(`/ids/${123}`)  //---->跳转至动态路由
        };
    };
    return { goMy , goIds};
  },
};
</script>
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值