天天看點

Vue3造輪子 項目筆記1.全局安裝 2.建立項目3.Vue2和Vue3的差別4.引入 Vue Router 45. Switch 元件(隻寫出個人筆記,具體内容看GitHub代碼)6. Button 元件7.Dialog 元件8.Tabs 元件9.事不過三,優化代碼。10.部署官網的過程11.Vue3官方文檔學習

目錄

1.全局安裝 

2.建立項目

3.Vue2和Vue3的差別

4.引入 Vue Router 4

安裝Vue Router

初始化Vue Router

對一個元件操作,實作另一個元件的出現和消失。實作功能的切換(出現或消失)。

路由切換後關閉"目錄"

路由嵌套

5. Switch 元件(隻寫出個人筆記,具體内容看GitHub代碼)

總結

6. Button 元件

7.Dialog 元件

8.Tabs 元件

9.事不過三,優化代碼。

10.部署官網的過程

11.Vue3官方文檔學習

1.全局安裝 

create-vite-appyarn global add [email protected]     或者

npm i -g [email protected]

2.建立項目

cva danjiamu-ui-1

cd danjiamu-ui-1

yarn

yarn dev

3.Vue2和Vue3的差別

  • Vue 3 的 Template 支援多個根标簽,Vue 2 不支援
  • Vue 3 有 createApp(),而 Vue 2 的是 new Vue()
  • createApp(元件),new Vue({template, render})

4.引入 Vue Router 4

安裝Vue Router

yarn add [email protected]

初始化Vue Router

main.ts檔案:

import {createRouter, createWebHashHistory} from 'vue-router'

const history = createWebHashHistory()//建立history
const router = createRouter(   //建立router
    {
        history:history,
        routes:[
            {path:'/',component:Frank},
            {path:'/xxx',component:Frank2}
        ]
    }
)



const app = createApp(App)
app.use(router)  //使用router
app.mount('#app')

//主要代碼是這些
           

app.vue檔案:

<template>
  <div>導航欄| <router-link to="/">Frank</router-link> | <router-link to="/xxx">Frank2</router-link></div>   //選中前往路徑
  <hr>
  <router-view/>  //渲染元件
</template>

<script >

export default {
  name: 'App',
 
}
</script>
           

對一個元件操作,實作另一個元件的出現和消失。實作功能的切換(出現或消失)。

App.vue:

import { createRouter, createWebHashHistory } from "vue-router";
import Home from "./views/Home.vue";
import Doc from "./views/Doc.vue";
import SwitchDemo from "./components/SwitchDemo.vue";
import ButtonDemo from "./components/ButtonDemo.vue";
import DialogDemo from "./components/DialogDemo.vue";
import TabsDemo from "./components/TabsDemo.vue";
import DocDemo from "./components/DocDemo.vue";

const history = createWebHashHistory();
export const router = createRouter({
  history: history,
  routes: [
    { path: "/", component: Home },
    {
      path: "/doc",
      component: Doc,
      children: [
        { path: "", component: DocDemo },
        { path: "switch", component: SwitchDemo },
        { path: "button", component: ButtonDemo },
        { path: "dialog", component: DialogDemo },
        { path: "tabs", component: TabsDemo },
      ],
    },
  ],
});
           

Doc.vue:

<script >
import { inject, Ref } from "vue";
import Topnav from "../components/Topnav.vue";
export default {
  components: { Topnav },
  setup() {
    const menuVisible = inject<Ref<boolean>>("menuVisible");
    return { menuVisible };
  },
};
</script>
           

Topnay.vue:

<template>
  <div class="topnav">
    <div class="logo" @click="toggleMenu">LOGO</div>
    <ul class="menu">
      <li>菜單1</li>
      <li>菜單2</li>
    </ul>
  </div>
</template>

<script >
import { inject, Ref } from "vue";

export default {
  setup() {
    const menuVisible = inject<Ref<boolean>>("menuVisible"); // get
    const toggleMenu = () => {
      menuVisible.value = !menuVisible.value;
    };
    return { toggleMenu };
  },
};
</script>
           

路由切換後關閉"目錄"

router.afterEach(() => {
      if (width <= 500) {
        menuVisible.value = false;
      }
    }
           

路由嵌套

import { createRouter, createWebHashHistory } from "vue-router";
import Home from "./views/Home.vue";
import Doc from "./views/Doc.vue";
import SwitchDemo from "./components/SwitchDemo.vue";
import ButtonDemo from "./components/ButtonDemo.vue";
import DialogDemo from "./components/DialogDemo.vue";
import TabsDemo from "./components/TabsDemo.vue";
import DocDemo from "./components/DocDemo.vue";

const history = createWebHashHistory();
export const router = createRouter({
  history: history,
  routes: [
    { path: "/", component: Home },
    {
      path: "/doc",
      component: Doc,
      children: [                                  //路由嵌套
        { path: "", component: DocDemo },
        { path: "switch", component: SwitchDemo },
        { path: "button", component: ButtonDemo },
        { path: "dialog", component: DialogDemo },
        { path: "tabs", component: TabsDemo },
      ],
    },
  ],
});
           

至此,整個官網架構基本完成。

5. Switch 元件(隻寫出個人筆記,具體内容看GitHub代碼)

    1.    css中        $h2:白色圓圈得寬度;   

        left:calc(100%-#{h2})   效果如下圖👇

Vue3造輪子 項目筆記1.全局安裝 2.建立項目3.Vue2和Vue3的差別4.引入 Vue Router 45. Switch 元件(隻寫出個人筆記,具體内容看GitHub代碼)6. Button 元件7.Dialog 元件8.Tabs 元件9.事不過三,優化代碼。10.部署官網的過程11.Vue3官方文檔學習

2. $event 的值是 emit 的第二個參數 emit(事件名, 事件參數)

//SwitchDemo.vue

<template>
  <Switch :value="y" @update:value="y = $event" />   
//上邊可以寫為<Switch v-model:value="y" />   使用v-model的簡寫

</template>

<script >
import { ref } from "vue";
import Switch from "../lib/Switch.vue";

export default {
  components: { Switch },
  setup() {
    const y = ref(false);
    return { y };
  },
};
</script>


----------------------------------------------------------------------------------------

//Switch.vue

<template>
  <button @click="toggle" :class="{ checked: value }"><span></span></button>
</template>

<script >
import { ref } from "vue";

export default {
  props:{                                  //接受外部資料value
    value:Boolean
  },
  setup(props,context) {
    const toggle = () => {
      context.emit('update:value',!props.value)  //emit将 input 事件 的新值傳給 $event
    }
    return {  toggle }
  },
};
</script>
           

總結

  • value="true" 和 :value="true" 的差別
  • 使用 CSS transition 添加過渡動畫
  • 使用 ref 建立内部資料
  • 使用 :value 和 @input 讓父子元件進行交流(元件通信)
  • 使用 $event
  • 使用 v-model
  • 架構就是把你框起來:不準改 props

•Vue 2 和 Vue 3 的差別

  • 新 v-model 代替以前的 v-model 和 .sync
  • 新增 context.emit,與 this.$emit 作用相同

6. Button 元件

  • 預設所有屬性都綁定到根元素
  • 使用 inheritAttrs: false 可以取消預設綁定
  • 使用 $attrs 或者 context.attrs 擷取所有屬性
  • 使用 v-bind="$attrs" 批量綁定屬性
  • 使用 const {size, level, ...xxx} = context.attrs 将屬性分開
<template>
  <div :size="size">
    <button v-bind="rest">
      <slot />
    </button>
  </div>
</template>

<script >
export default {
  inheritAttrs: false,    //取消預設綁定
  setup(props, context) {
    const { size, ...rest } = context.attrs;   //擷取所有屬性
    return { size, rest };   //rest為剩餘屬性
  },
};
</script>
           

7.Dialog 元件

visible屬性 表示是否可見

// DialogDemo.vue

<template>
  <div>DialogDemo 的文檔</div>
  <h1>示例1</h1>
  <Button @click="toggle">toggle</Button>
  <Dialog
    v-model:visible="x"
    :closeOnClickOverlay="false"
    :ok="f1"
    :cancel="f2"
  ></Dialog>
</template>

<script >
import Dialog from "../lib/Dialog.vue";
import Button from "../lib/Button.vue";
import { ref } from "vue";

export default {
  components: { Dialog, Button },

  setup(props) {
    const x = ref(false);
    const toggle = () => {
      x.value = !x.value;
    };
    const f1 = () => {
      return false;
    };
    const f2 = () => {};
    return { x, toggle, f1, f2 };
  },
};
</script>

----------------------------------------------------------------------------------------
//Dialog.vue

<template>
  <template v-if="visible">
    <div class="djm-dialog-overlay" @click="onClickOverlay"></div>
    <div class="djm-dialog-wrapper">
      <div class="djm-dialog">
        <header>
          标題
          <span @click="close" class="djm-dialog-close"></span>
        </header>
        <main>
          <p>第一行字</p>
          <p>第二行字</p>
        </main>
        <footer>
          <Button level="main" @click="ok">OK</Button>
          <Button @click="cancel">Cancel</Button>
        </footer>
      </div>
    </div>
  </template>
</template>

<script >
import Button from "./Button.vue";
export default {
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
    closeOnClickOverlay: {
      type: Boolean,
      default: true,
    },
    ok: {
      type: Function,
    },
    cancel: {
      type: Function,
    },
  },
  components: {
    Button,
  },
  setup(props, context) {
    const close = () => {
      context.emit("update:visible", false);
    };
    const onClickOverlay = () => {
      if (props.closeOnClickOverlay) {
        close();
      }
    };
    const ok = () => {
      if (props.ok?.() !== false) {
        close();
      }
    };
    const cancel = () => {
      context.emit("cancel");
      close();
    };
    return {
      close,
      onClickOverlay,
      ok,
      cancel,
    };
  },
};
</script>
           

8.Tabs 元件

  • 如何在運作時确認子元件的類型:檢查 context.slots.default() 數組
  • 用 JS 擷取插槽内容:const defaults = context.slots.default()
  • onMounted / onUpdated / watchEffect差別,自行查官方文檔
  • TypeScript 泛型: const indicator = ref <HTMLDivElement> (null)
  • 擷取寬高和位置: const { width, left } = el.getBoundingClientRect()
  • ES 6 析構指派的重命名文法

    const { left: left1 } = x. getBoundingClientRect()

    const { left: left2 } = y. getBoundingClientRect()

9.事不過三,優化代碼。

檢視源代碼

10.部署官網的過程

生成 dist:rm -rf dist; yarn build;

上傳 dist:cd dist 然後一堆 git 指令

                cd dist

                git init

                git add .

                git commit -m "first commit"

                git branch -M master

                git remote add origin 以git@開頭的倉庫位址

                git push -f -u origin master

                cd ..

預覽:打開 GitHub 提供的網址,有時還得重新整理幾次

11.Vue3官方文檔學習

  • 如何更新 Vue 2 到 Vue 3

蔣群豪 - vue從業人員github---vue2更新到vue3工具

官方文檔學習連結