# Vue ## UI Libraries - [Quasar](https://quasar.dev/) - [PrimeVue](https://primevue.org/) - [Naive UI](https://naiveui.com/) - [Shadcn](https://shadcn-vue.com/) - [Element Plus](https://element-plus.org), dashboard and admin - [Vuetify](https://vuetifyjs.com/) - [Chakra](https://vue.chakra-ui.com/) ## Config [`vuejs/tsconfig`](https://github.com/vuejs/tsconfig), Vue's recommended [[ts|TypeScript]] config. According to [documentation of `eslint-plugin-vue`](https://eslint.vuejs.org/user-guide/), we need to specify parser in `languageOptions`, and add `vue` as extra extension. ```ts import ts from "typescript-eslint"; export default ts.config( ... { languageOptions: { parserOptions: { extraFileExtensions: ["vue"], parser: ts.parser, projectService: true, }, }, }, ... ); ``` ## Development - Directives for handling events, with extended modifiers. - `$el` becomes available to refer to the DOM node once mounted. - A component will only unmount itself after all children unmount. - Use `ref` attribute point to a DOM element. `this.$ref.refName`. The reference instance contains all properties and methods of a specific DOM element (or all children components.) - Mixin - Define components to provide common functionalities to components. (No template, so possible to implement in `.js` or `.ts`). - Mixin hooks are invoked before components' hooks, and according to the order in mixins array. - Consider other alternatives. Mixins can affect performance. - Style - Use `:deep(p)` directive to apply styles to all children `p` element. - Scoped styles are not applied to slots by default. We can use `:slot([selector])` to force it. - Use pseudo class to reference a variable in styles: `color: v-bind(colorVar)` - Using CSS Modules with `<style module>` to make CSS rules accessible through `$style`. Modules can be assigned a name. - Creating composables for fetching data, and a `FetchComponent` with different slots to abstract the handling of loading/empty/error/content states. - Use `h` function (hyper-script) and functional components to have fine-grained control on the rendering process. ## Composing Component - `setup(props, context)` - Returns an object that contains all the references to the component's internal reactive state and methods and any static data. - `<script setup>` adds TypeScript supported by default. Variables defined in `setup(0)` don't have to be in `data()`. - Used to define stateless functional component. `return () => h('div', message)` - `beforeCreated()`, suitable for loading external logic without changing the component state. - `created()`, runs before first render, can perform tasks that require `this` binding. Suitable for loading external logic _into_ the component state. - `updated()` runs after render updates. Must not mutate component's state here. - `watch: { 'user.name': { handler() { ... } } }` to specify specific nested property to watch. - `this.$watch()` creates a watcher, returning a function to stop the watcher. ```vue <script lang="ts"> import { defineComponent } from "vue"; import MyComponent from "./components/MyComponent.vue"; // whatever defined here will be made available to the tempaltes // no this needed, no .values needed export default defineComponent({ name: "MyNewComponent", // template will be compiled to be part of the component template: "<div>Hello World!</div>", components: { MyComponent }, // make the component imported aware to template setup() { console.log("setup hook"); console.log(this); }, data() { // data passed to template are all static return { message: "a message to the template" }; }, emits: ["task-toggle"], // specify the emits // methods of the component, we can use `this` here methods: { onTaskCompleted(event: Event) { this.$emit("task-toggle", { // emit an event to the ...this.task, // we can use this completed: (event.target as HTMLInputElement)?.checked, }); }, }, watch: {}, // watchers provide: { providedVal: [1] }, // provide/inject props: { task: { type: Object as PropType<Task>, required: true, default: defaultTask, // validator: () => true // we can also add other validators }, }, // dataflow is one way only }); </script> ``` In setup script: ```vue <script lang="ts" setup> // we can use generic for type-only declaration const props = defineProps<PropsType>(); // similarly, we can have type-only emits declaration type EmitEvents = { (e: "task-toggle", task: Task): void }; const emits = defineEmits<EmitEvents>(); const onTaskCompleted = (event: Event) => { emits("task-toggle", { id: props.task.id, completed: (event.target as HTMLInputElement)?.checked, }); }; </script> ``` ## Composition API - `ref` for primitives, `shallowRef` for objects that needs observation, `reactive` for deeply reactive objects ## Special Tags - Slots - Inside the component: `<slot :var1="var1", :var2="var2>`, then we can use `v-slot="{ var1, var2 }"` to get the slot with it's parameters. - For more slots, we can name them and use `v-slot` directives in the templates. - Scoped styles of a component doesn't apply to the slot. - Use <teleport to='#modal' :disabled='!open'></teleport> to implement dialogs - Dynamically render component with `<component :is="componentName">`. - Keep states of an unmounted component alive with `<keep-alive>`