--- LocalWords: Vue DOM JS title: "LukeShu's Guide to Vue" author: - Luke T. Shumaker abstract: | There are 4 primary pieces to the official Vue documentation: 1. Guide 2. API 3. Style Guide 4. Examples The "Guide" is where concepts get introduced and explained; but fairly little of the underlying machinery or details are explained; or it is hard to find. The "API" is where the machinery and details are explained, but the concepts of how that fits together is missing; it links to the Guide. I think it's silly that those are 2 separate documents. --- # Introduction import Vue from 'vue'; Vue (pronounced like "view") is a *progressive* framework for building user interfaces; progressive means that you can use it for as much, or as little, of the user interface as you like. There are a few major object types in Vue that are helpful to understanding Vue at a high-level: - *Vue Instances*: a Vue instance manages a part of the DOM. - *Components*: think of components as "custom HTML ``s". An instance of a component is a type of Vue instance. That is, your custom `` obviously "owns" and manages the underlying real HTML elements in the DOM that are used to implement it. - *Directives*: think of directives as "custom HTML `attr="ibutes"`". In addition to those objects: - *Reactive*: Each *component* has a "data" object associated with it; this is usually just a plain map Object. If you (in the ordinary, plain, JS ways!) modify that object, the component will automatically *react* to that change, and update the DOM accordingly. - *Templates*: Vue has its own HTML templating language, that allows us to write markup such that Vue knows how to make it *reactive*. It's just plain HTML, but with (1) Vue-defined and user-defined custom elements (via *components*), and (2) Vue-defined and user-defined custom attributes (via *directives*). If you don't like writing raw HTML, that's fine, you could write it via PUG or any other compile-to-HTML language, since Vue templates are *just HTML*. From the JavaScript, they are just plain strings. - *Render functions*: Ultimately, *templates* compile to render functions. If your application design and toolchain (WebPack/Babel/what-have-you) allow it, this can be done ahead-of-time as a server-side optimization step before being served to the client, or it can happen at runtime by calling `Vue.compile("template string")`, which returns a function. Anyway, having render functions exposed to programmers means that, if you want, you can write the render functions yourself, instead of writing templates. Programmers coming from React will note that JSX is useful for writing render functions. Tying it together: A *component* is mostly just a *Vue instance* that manages its part of the DOM by calling a *render function* (compiled from a *template*) in accordance with an object that the component is assigned to be *reactive* to. The premise of Vue is that this small set of objects and concepts gives us the tools to effectively write dope-ass parts of a user-interface, without requiring is to use Vue to do the entire interface (though you could). # Major topics ## Reactivity Because of limitations in JavaScript, when implementing the magical reactivity that Vue provides, Vue can detect attribute *modification*, but not adding or removing attributes. Lame! So, Vue provides us with a couple of silly magic functions to work around this limitation: - `Vue.set(object, key, value);` is like `object[key] = value;`, except that if the `key` attribute doesn't exist yet, it is created as a reactive attribute, working around the limitation that Vue can't detect attribute additions. - `Vue.delete(object, key);` is like `delete object[key];`, but ensures that the deletion triggers view updates, working around the limitation that Vue can't detect attribute deletions. ## Root Vue Instance var vm = new Vue({ ... }); > As a convention, it is common to use the variable name `vm` for the > root Vue instance; `vm` stands for ViewModel; a reference to the > [Model+View+ViewModel (MVVM)][MVVM] application architecture; but > don't worry about MVVM, since from your point of view of, your Vue > program won't be following MVVM; just accept it as an arbitrary > convention. To use it, you will need to *mount* the instance to the part of the DOM that it will manage. You can do this after-the-fact like: vm.$mount("css-selector"); // the first matching element will be used // or vm.$mount(HTMLElement); Or, you can do it at instance creation by specifying `el`: var vm = new Vue({ el: CSS-selector-or-HTMLElement, }); The mount-point element will be *replaced* with the Vue-generated DOM, so it is therefore not recommended to mount the root instance to `` or ``. ## Components We define a component like var MyComponent = Vue.extend({ ... }); The things that go in the `...` are a superset of the things that we can pass to `new Vue({ ... })`. But that doesn't give it a name! We'll need to register our component with an HTML tag name. ### Global registration We register a component globally with: Vue.component('tag-name', MyComponent); > Vue does not enforce the rules on component names that are there > for [W3C Custom Element][W3C Custom Elements] tag names > (all-lowercase, must contain a hyphen), but it is conventional to > follow them anyway, and is considered good practice. Since it's so common to immediately register components, and not otherwise use them directly in the JS, we have a bit of shorthand that we can use for convenience: Vue.component('tag-name', Vue.extend({ ... })); // can be written as Vue.component('tag-name', { ... }); // and it will automatically call Vue.extend for us > Wait, that didn't actually save us much typing, and obscured the > fact that component creation and registration are two distinct > operations. Lame shorthand! If we want to be able to retrieve a component that we know is registered, but the current code doesn't have an object for, we can get it like: // returns the component previously registered to 'tag-name' var MyComponent = Vue.component('tag-name'); ### Scoped registration Of course, you may have had drilled in to your head "globals are bad". We can also register components locally to a Vue instance. TODO. ## Directives Unlike components, which are a specific object type that had to be created with `Vue.extend(...)`, directives are implemented as plain map objects. Which is a little confusing, since it means that directive registration looks like directive creation, and puts wrong notions in your head. ### Global registration Anyway, a directive can be registered globally: Vue.directive('directive-name', { ... }); The resulting attribute name always has a `v-` prefix; the above results in needing to set `v-directive-name="foo"`. ### Scoped registration TODO ## Mixins ## Templates > Unfortunately, that's custom ``s; with Vue > components, we can't use the `` shorthand, or > implied-closing (like with `
  • `). # Built-in ("core") directives TODO # Configuration - Global: `Vue.config` * Development Settings * `Vue.config.silent` Bool * `Vue.config.devtools` Bool * `Vue.config.warnHandler` Function * `Vue.config.performance` Bool * `Vue.config.productionTip` Bool * For-reals Settings * `Vue.config.optionMergeStrategies` Map * `Vue.config.errorHandler` Function * `Vue.config.ignoredElements` Array * `Vue.config.keyCodes` Map> # Bonus: Single File Components (SFC's) TODO Once upon a time, there was library that compiled SFCs in to JS modules (`vue-component-compiler`); there were a couple of 3rd-party stand-alone CLI wrappers for it. That compiler got merged in to `vueify` (the Browserify plugin for SFCs), and even though the compiler API is still exposed there, other bundler plugins don't share it. There's a new `vue-component-compiler` being developed, but it's not ready yet. That means we're left with 3 *separate* SFC "compilers" that are fairly tightly coupled with the bundle system they're designed for. I'm sure they don't contain any nasty differences. - WebPack (`vue-loader`): Presumed to be the flagship option. - Browserify (`vueify`): Vue 2.5.0 (2017-10-12) added the ability to write Functional Components as SFCs. That is not yet supported in Vueify. Three months isn't a long time, but we can surmise that Vueify is the ugly step child now. - Rollup (`rollup-plugin-vue`): TODO # misc Components don't work by literally registering custom elements with the browser (though a W3C spec exists for allowing that, it isn't (yet?) widely implemented). Instead, it's the *template language* that knows about them, the custom element names are registered with the template compiler, and the compiler then knows that when it encounters a node with that element name, it needs to emit a render function that instantiates that component. Ditto for directives. THE ABOVE IS FALSE. The render function calls `something.createElement("element-name")`, the components are registered with the `createElement`; the compiler doesn't need to know this. I'm a big advocate of learning about things by reading the source. Be aware that Vue is written in a JavaScript superset language called [Flow][] that adds typechecking, similar to TypeScript. When reading the official docs, their notation for types seemed a little weird to me; it seemed that Java-like notation would have more intuitively conveyed a few constructs--until I realized that they were using Flow notation. * Global API - `Vue.nextTick` - `Vue.filter` - `Vue.use` (plugins) - `Vue.mixin` - `Vue.version` return the Vue version as a String Vue instances may have a "render" function, or a "template". I believe that templates compile to a render function (via `vue-template-compiler`), either at run-time, or at bundle-time if possible. # options [MVVM]: https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel [W3C Custom Elements]: https://www.w3.org/TR/custom-elements/#concepts [Flow]: https://flow.org/