# 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>`