笔记 极客时间<<玩转Vue3全家桶>>

370 阅读3分钟

05项目启动 搭建vue3工程化项目

vite项目创建过程

  1. 下载node.js 选择LTS稳定版本 node -v验证是否安装成功
  2. vs code 安装插件 volar
  3. npm init @vitejs/app 创建vite项目 根据提示进行选择
Project name: 项目名称
Select a framework: 选择vue框架
Select a variant: 选择vue
  1. npm install && npm run dev 项目启动

  2. 安装vue-router 和 Vuex

    npm install vue-router@next vuex@next

我们所有工程化体系都是基于Node.js生态;我们使用VS Code + volar编辑器 + 语法提示工具作为上层开发工具;使用Vite作为工程化工具;使用Chrome进行调试

项目规范

  1. 组织结构
├── src
│   ├── api            数据请求
│   ├── assets         静态资源
│   ├── components     组件
│   ├── pages          页面
│   ├── router         路由配置
│   ├── store          vuex数据
│   └── utils          工具函数

07 巧妙的响应式: 深入理解vue 3的响应式机制

image.png

vueuse 工具包

function useStorage(name, value=[]){
    let data = ref(JSON.parse(localStorage.getItem(name)|| value))
    watchEffect(()=>{
        localStorage.setItem(name,JSON.stringify(data.value))
    })
    return data
}

vue中好多useXxx包都是基于组合Api搞出来的

npm install @vueuse/core

全屏


<template>
  <h1 @click="toggle">click</h1>
</template>
<script setup>
import { useFullscreen } from '@vueuse/core'
const { isFullscreen, enter, exit, toggle } = useFullscreen()
</script>

commonjs / ES Module

commonjs

  • 导出用 exports 或 module.exports

    exports指向 module.exports 最终导出由module.exports决定 exports只是指向

    exports.name = "abc" 
    exports.auth = "xxx" 
    exports.say = function(){}
    
    module.exports = {} //会清空
    
  • 导入用 required("xx.js")

    const demo = required("xx.js)
    demo.name
    

ES Module

export 导出 import 导入

export name = "aaa"
export default = {} //只有一个default
import {name} from "./a.js" 
import defaultvalue from "./a.js"

const a = import("./staticfil") //返回Promise对象 实现懒加载
a.then(res=>{})

import 'module' //不导出 只运行一次

10vuex

vuex的使用

  1. 创建store对象
//src/store.vue
        
import { createStore } from 'vuex'

const store = createStore({
  state () {
    return {
      count: 666
    }
  },
  getters:{  //可以直接用在computed中
      double(state){
          return state.count*2
      }
  },
  mutations: {
    add (state) {
      state.count++
    }
  }
})
export default store
  1. 注册到vue app实例上
const app = createApp(App)
app.use(store)
    .use(router)
    .mount('#app')
  1. 使用
<template>
<div @click="add">
    {{count}}
</div>
</template>

<script setup>
import { computed } from 'vue'
import {useStore} from 'vuex'
let store = useStore()
let count = computed(()=>store.state.count)

function add(){
    store.commit('add')
}
</script>

commit 对应 mutations

dispatch 对应 actions

手写vuex

import {inject,reactive} from 'vue'
//手写vuex
const STORE_KEY = '__store__'

function useStore(){
    return inject(STORE_KEY) //获取vue中的对象
}


class Store{
    constructor(options){
        this.$options = options
        this._state = reactive({
            data:options.state()
        })
        this._mutations = options.mutations
    }
    get state(){
        return this._state.data
    }
    commit = (type,payload) => {
        const entry = this._mutations[type]
        entry && entry(this.state,payload)
    }
    //app.use 时候会运行 直接注册到全局
    install(app){
        app.provide(STORE_KEY,this) 
    }
}

function createStore(options){
    return new Store(options)
}
export {createStore,useStore}

11 vue-router

原理

1 hash url中带#号 hashChange 监听函数
window.addEventListener('hashchange',fn)

2 history 正常url popstate 监听函数
window.addEventListener('popstate', fn)

vue-router 中对应两个函数,分别是 createWebHashHistory 和 createWebHistory

2014年 HTML5标准 两个 API pushState replaceState 改变URL地址 并且浏览器不会向后端发送请求

原理演示版

  1. 目录
-src
    -components
        cat.vue
        dog.vue
    - router
        index.js
        -grouter
            index.js
            RouterLink.vue
            RouterView.vue
app.vue
main.js     
  1. demo组件

    //cat.vue
    <template>
        <h1 style="color:red">
        this is cat
        </h1>
    </template>
    
    doc.vue
    <template>
        <h1 style="color:blue">
        this is dog
        </h1>
    </template>
    
  2. router组件编写

    //grouter/index.js
    import {ref,inject} from 'vue'
    const ROUTER_KEY = '__router__'
    import RouterLink from './RouterLink.vue'
    import RouterView from './RouterView.vue'
    
    
    function createWebHashHistory(){
       function bindEvents(fn){
           window.addEventListener('hashchange',fn)
       }
       return{
           bindEvents,
           url: '/'
       }
    }
    class Router{
       constructor(options){
           this.history = options.history //createWebHashHistory {bindEvents: url:}
           this.routes = options.routes
           this.current = ref(this.history.url)  //关键 current为响应式变量
    
           this.history.bindEvents(()=>{ //监听路径改变 改变current值 
               this.current.value = window.location.hash.slice(1)
           })
       }
       install(app){
           app.provide(ROUTER_KEY,this) //注册实例 只有一个
           app.component("router-link",RouterLink) //注册组件 可以重复使用        
           app.component("router-view",RouterView) 
       }
    }
    
    //
    function createRouter(options){
       return new Router(options)
    }
    
    //
    function useRouter(){
       return inject(ROUTER_KEY)
    }
    
    export {createRouter,createWebHashHistory,useRouter}
    

    1 window.addEventListener 绑定 hash变化事件函数

    2 hash变化后把当前hash值赋值给router中的响应对象 current

    3 routerView组件监听current

3 routerView.vue

//RouterView.vue
<template>
   <component :is="comp">
   </component>
</template>
<script setup>
   import {computed} from 'vue'
   import {useRouter} from '../grouter/index'

   let router = useRouter()
   const comp = computed(()=>{
       const route = router.routes.find(
           (route) =>return route.path === router.current.value
       )
       return route?route.component:null
   })

</script>

通过computed监听router.current,通过component内置组件进行自定义组件(cat.vue,dog.vue)显示

  1. RouterLink.vue
// RouterLink.vue
 
 <template>
    <a :href="'#'+props.to">
        <slot />
    </a>
</template>
<script setup>
import { defineProps } from 'vue';
let props = defineProps({
    to:{type:String,required:true}
})
</script>

改变hash值 自动触发绑定的hash事件函数

  1. 路由配置
//router/index.js
import{
   createRouter,
   createWebHashHistory,
} from './grouter/index'

import dog from '../components/dog.vue'
import cat from '../components/cat.vue'



export default createRouter({
   history:createWebHashHistory(),
   routes:[{
       path:"/dog",
       component:dog,
   },{
       path:"/cat",
       component:cat,
   }

   ]
})
  1. app.vue
 //app.vue
<template>
   <router-link to="/dog">
    DOG
  </router-link>
    <router-link to="/cat">
    CAT
  </router-link>
  
  <router-view></router-view>
</template>
  1. main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')