vite 创建项目流程 + vue3学习

1. 创建vite项目  

        cmd打开终端

        npm init vite

        输入项目名

        选择vue框架

        选择使用js

2. 打开项目文件  配置路由

        npm i   初始化项目

        npm install vue-router   安装路由

       新建router文件   创建index.js

       内容:

import {createRouter,createWebHashHistory} from "vue-router";

const routes = [
  {
    path: "/",
    redirect: "/login",
  },
  {
    path: "/login",
    name: "login",
    component: () => import("../views/login.vue"),
  },
]

const router = createRouter({
  history: createWebHashHistory(),
  routes,
});
export default router;

main.js中引入router    createvue后面加上use(router)

在app.vue页面加上router-view  显示路由界面

3. 配置页面

        创建views文件夹存放页面  

        创建路由中的vue页面

4. vite.config.js配置文件的基本设置:

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { resolve } from "path";
// 引入自动导入import的插件
import AutoImport from "unplugin-auto-import/vite";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      imports: ["vue", "vue-router"],
    }),
  ],
  // 配置代理解决跨域问题
  server: {
    proxy: {
      "/api": {
        target: "https://test.ktyfz.com/",
        changeOrigin: true,
        // rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
    // host: 'localhost', //设置域名
    host: "0.0.0.0",
    // open: true, //设置自动打开
    port: 8090, //端口
    hmr: true, //开启热更新
  },

  build: {},

  // 配置别名 @
  resolve: {
    alias: {
      "@": resolve(__dirname, "src"),
    },
  },
});

vue3学习:

响应式数据:

reactive:

import { reactive } from 'vue'

const state = reactive({ count: 0 })

reactive() 的局限性:

1.仅对对象类型有效(对象、数组和 MapSet 这样的集合类型),而对 stringnumber 和 boolean 这样的 原始类型 无效

2.

ref: 定义响应式简单数据类型使用ref   在使用时需要.value进行使用、

 watch

监听单个数据:

watch(str, (newvalue, oldvalue) => {
  console.log(newvalue, oldvalue);
})

监听多个数据:

watch([str1, str2], (newvalueArr, oldvalueArr) => {
  console.log(newvalueArr, oldvalueArr);
  //newvalueArr为新值的数组  第一项为str1  第二项为str2
  //oldvalueArr为旧值的数组  第一项为str1  第二项为str2
})

监听对象中的某个key的值的变化:

// 监听 obj中key属性的值
watch(() => obj.key, (newvalue, oldvalue) => {
  console.log(newvalue, oldvalue);
})
//obj.key也可写成obj['key']

当需要立即监听和深度监听时 :

watch(() => obj['key'], (newvalue, oldvalue) => {
  console.log(newvalue, oldvalue);
}, {
  immediate: true,
  deep:true
//当obj.key(obj['key'])的值为一个对象时  需要用到深度监听
})

动态组件:

使用<compontent  :is='组件名'> 控制显示的组件  可使用KeepAlive内置组件进行缓存

(组件要引入)

异步组件:

使用场景1:

例如:页面包含A、B、C三个组件 ,当用户没下拉访问到C组件时 ,就不加载C组件,达到优化性能的效果

1.异步引入组件

import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() =>
  import('./components/MyComponent.vue')
)

虽然异步引入了组件 但是C组件也进行了加载  需要安装个插件 进行观察

1.需要安装@vueuse/core插件 

参考连接:https://vueuse.org/core/useIntersectionObserver/#demo

并在父组件中引入

import  {useIntersectionObserver}  from ‘@vueuse/core’

<template>
    <div>
        <A></A>
        <B></B>
        <!-- 注意加上ref= 'target'-->
        <div ref="target">
            <C v-if="targetIsVisible"></C>
        </div>
    </div>
</template>
 
<script setup>

import { defineAsyncComponent, ref } from 'vue';

//1、 引入A B C组件  其中C使用异步加载
import A from '@/components/A.vue'
import B from '@/components/B.vue'
const C = defineAsyncComponent(() =>
    import('@/components/C.vue')
)

// 引入观察器 (@vueuse/core中)
import { useIntersectionObserver } from '@vueuse/core'
const target = ref(null)
//C组件的加载条件默认为false
const targetIsVisible = ref(false)
// 侦听 滑动到C组件时  isIntersecting会变成true
const { stop } = useIntersectionObserver(
    target,
    ([{ isIntersecting }]) => {
        // 判断 当isIntersecting变为true时  将C组件的加载条件设置为true
        if (isIntersecting) {
            targetIsVisible.value = isIntersecting
        }
    },
)
</script>
 
<style lang = 'less' scoped></style>

以上就实现了  当下滑到C组件时才开始加载C组件的内容

使用场景2:分包  run build时 异步组件会单独打包js文件(从主体js文件中分出来的)   仅在页面需要它渲染时才会调用加载内部实际组件的函数

搭配 Suspense  内置组件 使用

<Suspense> 组件有两个插槽:#default 和 #fallback。两个插槽都只允许一个直接子节点。在可能的时候都将显示默认槽中的节点。否则将显示后备槽中的节点。

<Suspense>
  <!-- 具有深层异步依赖的组件 -->
  <component />

  <!-- 在 #fallback 插槽中显示 “正在加载中” -->
  <template #fallback>
    加载中...
  </template>
</Suspense>

示例:

A中使用awiat操作发送axios请求  可将A组件写成异步加载组件 搭配Suspense内置组件使用  在响应数据回来之前显示 #fallback插槽的加载状态

A组件:

<template>
    <div class="A_page">
        {{ list }}
    </div>
</template>
 
<script setup>

import axios from 'axios';
import { reactive, ref } from 'vue';

const list = ref([])

// setup上 已经有async  所以内部可直接使用await
let res = await axios.get('http://xxxxxx/api/xxx/xxx')
list.value = res.data.data


</script>
 
<style lang = 'less' scoped>
.A_page {
    height: 60vh;
    background-color: pink;
}
</style>

父组件:

<template>
    <div>
        <!--A中使用awiat操作发送axios请求  可将A组件写成异步加载组件 搭配Suspense内置组件使用  在响应数据回来之前显示 #fallback插槽的加载状态  -->

        <Suspense>
            <template #default>
                <!-- 具有深层异步依赖的组件 -->
                <A></A>
            </template>

            <!-- 在 #fallback 插槽中显示 “正在加载中” -->
            <template #fallback>
                加载中...
            </template>
        </Suspense>
        <B></B>

        <!-- 注意加上ref= 'target'-->
        <div ref="target">
            <C v-if="targetIsVisible"></C>
        </div>

    </div>
</template>
 
<script setup>

import { defineAsyncComponent, ref } from 'vue';

//1、 引入A B C组件  其中A、C使用异步加载

 const A = defineAsyncComponent(() =>
     import('@/components/A.vue')
 )
import B from '@/components/B.vue'
const C = defineAsyncComponent(() =>
    import('@/components/C.vue')
)

// 引入观察器 (@vueuse/core中)
import { useIntersectionObserver } from '@vueuse/core'
const target = ref(null)
//C组件的加载条件默认为false
const targetIsVisible = ref(false)
// 侦听 滑动到C组件时  isIntersecting会变成true
const { stop } = useIntersectionObserver(
    target,
    ([{ isIntersecting }]) => {
        // 判断 当isIntersecting变为true时  将C组件的加载条件设置为true
        if (isIntersecting) {
            targetIsVisible.value = isIntersecting
        }
    },
)
</script>
 
<style lang = 'less' scoped></style>

当需要C异步组件使用await并在加载时也加上加载状态的  可以将vueuse中的观察器与Suspense结合使用

 <!-- 异步组件搭配vueues中的观察器一起使用 -->
        <!-- 异步组件使用 Suspense内置组件包裹-->
        <div ref="target">
            <Suspense v-if="targetIsVisible">
                <template #default>
                    <!-- 具有深层异步依赖的组件 -->
                    <C></C>
                </template>

                <!-- 在 #fallback 插槽中显示 “正在加载中” -->
                <template #fallback>
                    加载中...
                </template>
            </Suspense>
        </div>

Mixins 混入:

一个包含组件选项对象的数组,这些选项都将被混入到当前组件的实例中 组件引入后不相互共享

示例:

src下新建mixin/mixin.js

import { ref } from "vue";

export default function () {
  let num = ref(1);

  let fav = ref(false);

  let changeNum = () => {
    num.value++;
    fav.value = !fav.value;
  };

  return {
    num,
    fav,
    changeNum,
  };
}

使用:

A组件中引入并使用:

<template>
    <div class="A_page">
        <button @click="changeNum">按钮</button>
        {{ num }}---{{ fav }}
    </div>
</template>
 
<script setup>

import axios from 'axios';
import { reactive, ref } from 'vue';
import mixin from '@/mixins/mixins.js'//引入mixin
let { num, fav, changeNum } = mixin()//解构

</script>

当B组件也引入使用mixin时  其中使用的变量或方法不会互通

当mixin中有生命周期组件中也有生命周期时  会先执行mixin中的生命周期  再执行组件的生命周期

组件通讯   (<script setup>语法糖中的写法):

子传父:

父组件:

 <A :msg="msg"></A>

子组件接收:

const props = defineProps({
    msg: {
        type: String,
        default: '默认值'
    }
})

// 接收后可以进行解构  然后直接使用 不需要props.msg
let { msg } = props

子传父:

子组件:使用defineEmits  可以传入多个

const sonStr = ref('我是子组件的str')
const emit = defineEmits(['fn1', 'fn2'])

const clickHandler = () => {
    emit('fn1', sonStr.value)
}
const clickHandler2 = () => [
    emit('fn2')
]

父组件中:

 <A :msg="msg" @fn1="fatherFn" @fn2="fatherFn2"></A>


// 子传父后需要触发的事件1  接收参数
let fatherFn = (str) => {
    console.log('父组件接收到的str', str);
}

// 子传父需要触发的事件2
let fatherFn2 = () => {
    console.log('触发的事件2');
}

v-model双向传值:

父组件:

<A v-model:msg="msg"></A>


const msg=ref('我是父组件的msg')

子组件:

// 1.接收父组件传过来的数据
const props = defineProps({
    msg: {
        type: String,
        default: '默认值'
    }
})
// 使用 defineEmits 要在子组件修改msg  update:msg   update为固定写法 写成其他的无效
const emit = defineEmits(['update:msg'])

const sonChangeFn = () => {
    emit('update:msg', '子组件修改了msg')
}

兄弟组件之间传值:

此处为使用插件形式的示例:

1.下载安装 mitt 插件

npm install mitt -S

新建一个utils/Bus.js

import mitt from 'mitt'

const busEmitter =mitt() //调用一下mitt

export default busEmitter;

兄弟组件  A---B

A组件中:

import busEmitter from '@/utils/Bus.js'


const msg=ref('我是A组件的msg')

busEmitter.emit('fn',msg)

B组件中接收:

import busEmitter from '@/utils/Bus.js'

onBeforeMount(() => {
    busEmitter.on('fn', e => {
        console.log(e.value);
    })
})

爷孙组件传值 : provide+inject  依赖注入

父组件:

import {provide} from 'vue'
const msg = ref('我是父组件上的msg');
provide('sendMsg',msg)// 

子组件:

import {inject} from 'vue'

const myMsg=inject('sendMsg')

console.log(myMsg)

注入方可以修改提供方提供的数据

如果你想确保提供的数据不能被注入方的组件更改,你可以使用 readonly() 来包装提供的值。

import { ref, provide, readonly } from 'vue'

const count = ref(0)
provide('read-only-count', readonly(count))

Vuex:

1.安装vuex

npm install vuex

2.新建/store/inde.js

import { createStore } from "vuex";

export default createStore({
  state: {
    num: 1,
  },
  getters: {},
  mutations: {
    change(state) {
      state.num += 1;
    },
  },
  actions: {
    changeNumAsync(content) {
      setTimrout(() => {
        content.state.num += 2;
      }, 1000);
    },
  },
  modules: {},
});

在组件中使用:

pinia使用:

1.pinia没有mutations,只有state、getters、action,

2.pinia分模块不需要modules

3.pinia支持直接修改state的数据 不经过action

1.安装pinia

npm install pinia

2.在main.js中引入使用

import { createPinia } from "pinia"; //引入pinia

createApp(App).use(router).use(ElementPlus).use(createPinia()).mount("#app");

3.store/index.js中

import { defineStore } from "pinia";

export const useStore = defineStore("storeId", {
  state: () => {
    return {
      number1: 10,
      storeName: "Eduardo",
      isAdmin: true,
    };
  },
  getters: {},
  // Action 相当于组件中的 method  action 也可通过 this 访问整个 store 实例
  actions: {
    changehandler() {
      this.number1++;
    },
  },
});

4.组件中使用:

import { useStore } from '@/store/index'
const store = useStore();
const { number1 } = store.number1;//结构使用store中的数据

//clickHandler为组件中的点击事件
const clickHandler = () => {
    store.changehandler()//直接调用pinia中 action中的方法
}

5.组件中直接修改store中的数据:

结构出来的数据需要使用storeToRefs转为proxy

import { useStore } from '@/store/index'
import { storeToRefs } from 'pinia'

const store = useStore();
const { number1 } = storeToRefs(store);//解构使用store中的数据
console.log(store, 66666);

const clickHandler3 = () => {
    // 直接修改store中的数据  注意:解构出来要使用storeToRefs转为响应式
    number1.value += 5
}

批量修改:

const batchChange = () => {
    //批量更新
	store.$patch(state=>{
		state.number1++;
		state.isAdmin=false;
		state.storeName = '你好世界';
	})
}

pinia分模块  使用不同的js文件即可   user.js  、cart.js....

pinia持久化:插件形式

1.安装插件

npm i pinia-plugin-persist --save

2.store/index.js

import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'

const store = createPinia()
store.use(piniaPluginPersist)

export default store

3.main.js中修改

store import store from './store'

createApp(App).use(router).use(ElementPlus).use(store).mount("#app");

4.在对应模块中开启数据存储

store/user.js

import {defineStore} from ''pinia

export const useUserStore = defineStore({
  id: 'user',

  state: () => {
    return {
      name: '张三'
    }
  },
  
  // 开启数据缓存
  persist: {
    enabled: true
  }
})

自定义key:

persist: {
  enabled: true,               //开启数据持久化
  strategies: [
    {
      key: 'my_user',           //存储时的key命名
      storage: localStorage,    //默认存在sessionstorage中  可改为localStorage
    }
  ]
}

持久化局部 state

默认所有 state 都会进行缓存,你能够通过 paths 指定要长久化的字段,其余的则不会进行长久化。

persist: {
  enabled: true,
  strategies: [
    {
      storage: localStorage,
      paths: ['name', 'age']    //要执行持久化的数据变量
    }
  ]

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值