技术控

    今日:173| 主题:49347
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] Getting up and Running with the Vue.js 2.0 Framework

[复制链接]

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
This article is by guest author Jack Franklin . SitePoint guest posts aim to bring you engaging content from prominent writers and speakers of the JavaScript community
   Back in September, the popular JavaScript framework Vue.js released v2 and ever since I've been really eager to give it a spin and see what it's like to work with. As someone who's pretty familiar with Angular and React, I was looking forward to seeing the similarities and differences between them and Vue.
  Vue.js 2.0 sports excellent performance stats, a relatively small payload (the bundled runtime version of Vue weighs in at 16kb once minified and gzipped), along with updates to companion libraries like vue-router and vuex, the state management library for Vue. There's far too much to cover in just one article, but keep an eye out for a later article where we'll look more closely at some of the libraries that couple nicely with the core framework.
  Inspiration from Other Libraries

  As we go through this tutorial you'll see many features that Vue has that are clearly inspired by other frameworks. This is a good thing; it's great to see new frameworks take some ideas from other libraries and improve on them. In particular, you'll see Vue's templating is very close to Angular, but its components and component lifecycle methods are closer to React (and Angular 2, as well).
   One such example of this is that, much like React and nearly every framework in JavaScript land today, Vue uses the idea of a virtual DOM to keep rendering efficient. Vue uses a fork of snabbdom , one of the more popular virtual DOM libraries. The Vue site includes documentation on its Virtual DOM rendering , but as a user all you need to know is that Vue is very good at keeping your rendering fast (in fact, it performs better than React in many cases), meaning you can rest assured you're building on a solid platform.
  Components, Components, Components

   Much like other frameworks these days, Vue's core building block is the component. Your application should be a series of components that build on top of each other to produce the final application. Vue.js goes one step further by suggesting (although not enforcing) that you define your components in a single .vue file, which can then be parsed by build tools (we'll come onto those shortly). Given that the aim of this article is to fully explore Vue and what it feels like to work with, I'm going to use this convention for my application.
  A Vue file looks like so:
  [code] [/code]   Alternatively, you can give each element a src attribute and point to a separate HTML, JS or CSS file respectively if you don't like having all parts of the component in one file.
  Setting up a Project

  Whilst the excellent [Vue CLI][https://github.com/vuejs/vue-cli] exists to make setting up a full project easy, when starting out with a new library I like to do it all from scratch so I get more of an understanding of the tools.
   These days Webpack is my preferred build tool of choice, and we can couple that with the vue-loader plugin to support the Vue.js component format that I mentioned previously. The final thing we'll need is Babel and the ES2015 preset, so we can write all our code in lovely ES2015 syntax.
  Setting up the Webpack configuration boils down to the following:
  
       
  • Make Webpack build from src/main.js , and output into build/main.js   
  • Tell Webpack to use the vue-loader for any .vue files   
  • Tell Webpack to use Babel for any .js files   
  • Tell the vue-loader that it should use Babel to transpile all JavaScript. This means that when we include JavaScript in our *.vue files, it will be transpiled through Babel.  
  [code]module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }[/code]  Finally, we'll create an HTML file and we're ready to go!
   We create an empty div with the ID of app as this is the element that we're going to place our Vue application in. I always prefer to use a div , rather than just the body element, as that lets me have control over the rest of the page.
  Writing Our First Vue.js 2.0 App

  We're going to stay true to every programming tutorial ever and write a Vue application that puts "Hello World" onto the screen before we dive into something a bit more complicated.
   Each Vue app is created by importing the library and then instantiating a new Vue instance:
  [code]import Vue from 'vue' const vm = new Vue({ el: '#app', })[/code]   We give Vue an element to render onto the page, and with that, we've created a Vue application! We pass a selector for the element that we want Vue to replace with our application. This means when Vue runs it will take the div#app that we created and replace it with our application.
   The reason we use the variable name vm is because it stands for "View Model". Although not strictly associated with the "Model View View-Model" (MVVM) pattern , Vue was inspired in part by it, and the convention of using the variable name vm for Vue applications has stuck. Of course, you can call the variable whatever you'd like!
   So far, our application isn't doing anything, though, so let's create our first component, App.vue , that will actually render something onto the page.
   Vue doesn't dictate how your application is structured, so this one is up to you; I ended up creating one folder per component, in this case App (I like the capital letter, signifying a component), with four files in it:
   App/index.vue simply imports the other three files:
   I like calling it index.vue , but you might want to call it app.vue too so it's easier to search for. I prefer importing App/index.vue in my code versus App/app.vue , but again you might disagree, so feel free to pick whatever you and your team like best.
   For now, our template is just

Hello World

, and I'll leave the CSS file blank. The main work goes into script.js , which looks like so:
  [code]export default { name: 'App', data() { return {} }, }[/code]   Doing this creates a component which we'll give the name App , primarily for debugging purposes, which I'll come onto later, and then define the data that this component has and is responsible for. For now, we don't have any data, so we can just tell Vue that by returning an empty object. Later on, we'll see an example of a component using data.
   Now we can head back into src/main.js and tell the Vue instance to render our App component:
  [code]import Vue from 'vue' import AppComponent from './App/index.vue' const vm = new Vue({ el: '#app', components: { app: AppComponent, }, render: h => h('app'), })[/code]  Firstly, we import the component, trusting Webpack and the vue-loader to take care of parsing it. We then declare the component. This is an important step: by default, Vue components are not globally available. Each component must have a list of all the components they are going to use, and the tag that it will be mapped to. In this case, because we register our component like so:
  [code]components: { app: AppComponent, }[/code]   This means that in our templates we'll be able to use the app element to refer to our component.
   Finally, we define the render function. This function is called with a helper, commonly referred to as h , that is able to create elements. It's not too dissimilar to the React.createElement function that React uses. In this case, we give it the string 'app' , because the component we want to render is registered as having the tag app .
   More often than not (and for the rest of this tutorial) we won't use the render function on other components because we'll define HTML templates, but the Vue.js guide on the render function is worth a read if you'd like more information.
  Once we've done that, you should see "Hello World" on the screen, and we're up and running with Vue.js!
  Vue Devtools

   Before we dive into a slightly more complicated app with Vue, now is a good time to mention that you should definitely get the Vue Devtools installed. These sit within the Chrome developer tools and give you a great way to look through your app and all the properties being passed round, state that each component has, and so on.
   
Getting up and Running with the Vue.js 2.0 Framework-1 (management,framework,released,familiar,Running)

  Building the App

  As an example application, we're going to be using the GitHub API to build an application that lets us enter a username and see some GitHub stats about that user. I've picked the Github API here as it's familiar to most people, usable without authenticating, and gives us a fair amount of information.
   Before starting an application I like to have a quick think about what components we'll need, and I'm thinking that our App component will render two further components: GithubInput , for taking input from the user, and GithubOutput , which will show the user's information on the screen. We'll start with the input.
  Forms in Vue.js

   First, we'll create src/GithubInput/index.vue that loads the template, script and CSS file for our component. When creating this component the one thing we do differently is create a piece of data that's associated with the component - this is very similar to React's concept of state:
  [code]export default { name: 'GithubInput', data() { return { username: '', } } }[/code]   This says that this component has a piece of data, username , that it owns and is responsible for. We'll update this based on the user's input shortly.
   The template, src/GithubInput/template.html , simply contains

github input

for now. We'll fill it in properly shortly. I like putting in some dummy HTML so I can check I've got the template wired up properly when creating a new component.
   Finally, to get this component onto the screen, I need to register it with the App component, as it's the App component that will be rendering it.
   To do this I update src/App/script.js and tell it about GithubInput :
  [code]import GithubInput from '../GithubInput/index.vue' export default { name: 'App', components: { 'github-input': GithubInput, }, data() { return {} }, }[/code]  And then I can update the app component's template:
  [code]

Hello World

[/code]   A restriction of Vue components (which is also true in Angular and React) is that each component must have one root node, so when a component has to render multiple elements it's important to remember to wrap them all in something, most commonly a div .
  Tracking a Form Input

   Our GithubInput component will need to do two things:
  
       
  • Keep track of the current value of the input   
  • Communicate that the value has changed, so that other components can know and therefore update their state.  
   We can do the first version by creating a form with an input element in it. We can use Vue's built-in directives that enable us to keep track of form values. The template for GithubInput looks like so:
   There are two important attributes that you'll notice: v-on and v-model .
   v-on is how we bind to DOM events in Vue and call a function. For example,

Click me!

would call the component's foo method every time the paragraph was clicked. If you'd like to go through event handling in greater detail, I highly recommend the Vue documentation on event handling .
   v-model creates a two-way data binding between a form input and a piece of data. Behind the scenes, v-model is effectively listening for change events on the form input and updating the data in the Vue component to match.
   Taking our template above into consideration, here's how we're using v-on and v-model to deal with the data in the form:
  
       
  • v-on:submit.prevent="onSubmit" binds the method onSubmit to be run when the form is submitted. By adding .prevent that means that Vue will automatically prevent the default action from occurring (if Vue didn't do this we could call event.preventDefault() in our code, but we might as well take advantage of Vue's feature).   
  • v-model:username binds the input's value to a value, username , in our code. For those of you familiar with Angular you may recognize this as very similar to ng-model . When we created GithubInput we declared that it had a piece of data, username , and here we've bound that piece of data to the input field. The two will automatically be kept in sync.  
   Now, back in our component's JavaScript, we can declare the onSubmit method. Note that the name here is entirely arbitrary - you can choose whatever you'd like - but I like to stick with the convention of naming the function after the event that will trigger it.
  [code]name: 'GithubInput', methods: { onSubmit(event) { if (this.username && this.username !== '') { } } },[/code]   We can refer to data directly on this , so this.username will give us the latest value of the text box. If it's not empty, we want to let other components know that the data has changed. For this, we'll use a message bus. These are objects that components can emit events on and listen to other events. When your application grows larger you might want to look into a more structured approach, such as Vuex , and in a future tutorial, we will do just that. For now, a message bus does the job.
   The great news is that we can use an empty Vue instance as a message bus, as recommended in the Vue docs . We'll create src/bus.js which simply creates a Vue instance and exports it:
  [code]module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }0[/code]   In GithubInput we can then import that module and use it by emitting an event when the username changes:
  [code]module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }1[/code]  With that our form is done, and we're ready to start doing something with the resulting data.
  Displaying Results from GitHub

   We'll create the GithubOutput component, using the same structure as we've used previously. In GithubOutput/script.js we also import the bus module, as we'll need it to know when the username changes. The data that this component will be responsible for will be an object that maps GitHub usernames to the data we got from the GitHub API. This means we won't have to make the request to the API every single time; if we've already fetched the data previously we can simply reuse it. We'll also store the last username we were given, so we know what data to display on screen.
  [code]module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }2[/code]   When the component is created we want to listen for any new-username events that are emitted on the message bus. Thankfully, Vue supports a number of lifecycle hooks , including created . Because we're responsible developers let's also stop listening for events when the component is destroyed by using the destroyed event:
  [code]module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }3[/code]   We then define the onUsernameChange method which will be called, and will set the currentUsername property:
  [code]module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }4[/code]   Note that we don't have to explicitly bind the onUsernameChange method to the current scope. When you define methods on a Vue component, Vue automatically calls myMethod.bind(this) on them, so they are always bound to the component. This is one of the reasons why you need to define your component's methods on the methods object, so Vue is fully aware of them and can set them up accordingly.
  Conditional Rendering

   If we don't have a username, like we won't when the component is first created, we want to show a message to the user. Vue has a number of conditional rendering techniques , but the easiest is the v-if directive, which takes a condition and will only render the element if it exists. It also can be paired with v-else :
  [code]module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }5[/code]   Once again, this will look very familiar to any Angular developers. We use double equals rather than triple equals here because we want the conditional to be true not only if currentUsername is null but also if it's undefined, and null == undefined is true .
  Fetching from GitHub

   Vue.js doesn't ship with a built-in HTTP library, and for good reason. These days the fetch API ships natively in many browsers (although at the time of writing, not IE11, Safari or iOS Safari). For the sake of this tutorial I'm not going to use a polyfill, but you can easily polyfill the API in browsers if you need to. If you don't like the fetch API there are many third party libraries for HTTP and the one mentioned in the Vue docs is Axios .
  I'm a big proponent of frameworks like Vue not shipping with HTTP libraries; it keeps the bundle size of the framework down and leaves it to developers to pick the library that works best for them, and easily customize requests as needed to talk to their API. I'll stick to the fetch API in this article, but feel free to swap it out for one that you prefer.
   If you need an introduction to the fetch API, check out Ludovico Fischer's article on SitePoint which will get you up to speed.
   To make the HTTP request we'll give the component another method, fetchGithubData , that makes a request to the GitHub API and stores the result. It will also first check to see if we already have data for this user, and not make the request if so:
  [code]module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }6[/code]  We then finally just need to trigger this method when the username changes:
  [code]module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }7[/code]   There's one other thing to be aware of, due to the way that Vue keeps track of the data you're working with so that it knows when to update the view. There is a great Reactivity guide which explains it in detail, but essentially Vue isn't able to magically know when you've added or deleted a property from an object, so if we do:
  [code]module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }8[/code]   Vue won't recognize that and won't update our view. Instead, we can use the special Vue.set method, which explicitly tells Vue that we've added a key. The above code looks would then look like so:
  [code]module.exports = { entry: './src/main', output: { path: './build', filename: 'main.js', }, module: { loaders: [ { test: /\.vue$/, loader: 'vue', }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/, }, ], }, vue: { loaders: { js: 'babel', }, }, }9[/code]   This code will modify this.githubData , adding the key and value that we pass it. It also notifies Vue of the change so it can rerender.
  Now our code looks like so:
  [code]import Vue from 'vue' const vm = new Vue({ el: '#app', })0[/code]  Although we haven't yet written the view code to show this data on screen, you should be able to fill in the form with your username and then inspect the Vue dev tools to see the data requested from Github. This shows how useful and powerful these dev tools are; you can inspect the local state of any component and see exactly what's going on.
  Showing some stats in the view

   We can now update the template to show some data. Let's wrap this code in another v-if directive so that we only render the data if the request has finished:
  [code]import Vue from 'vue' const vm = new Vue({ el: '#app', })1[/code]  With that, we can now render the GitHub details to the screen, and our app is complete!
  Refactors

  There are definitely some improvements we can make. The above bit of HTML that renders the GitHub data only needs a small part of it - the data for the current user. This is the perfect case for another component that we can give a user's data to and it can render it.
   Let's create a GithubUserData component, following the same structure as with our other components. There's only one tiny difference - this component is going to take a property, data , which will be the data for the user. Properties (or, "props") are bits of data that a component will be passed by its parent, and behave in Vue much like they do in React. In Vue you have to explicitly declare each property that a component needs, so here I'll say that our component will take one prop, data :
  [code]import Vue from 'vue' const vm = new Vue({ el: '#app', })2[/code]  One thing I really like about Vue is how explicit you have to be; all properties, data, and components that a component will use are explicitly declared. This makes the code much nicer to work with and, I imagine, much easier as projects get bigger and more complex.
   In the new template, we have exactly the same HTML as before, although we can refer to data rather than githubData[currentUsername] :
  [code]import Vue from 'vue' const vm = new Vue({ el: '#app', })3[/code]   To use this component we need to update the GithubOutput component. Firstly, we import and register GithubUserData :
  [code]import Vue from 'vue' const vm = new Vue({ el: '#app', })4[/code]   You can use any name for the component when declaring it, so where I've placed github-user-data , you could place anything you want. It's advisable that you stick to components with a dash in them. Vue doesn't enforce this, but the W3C specification on custom elements states that they must contain a dash to prevent naming collisions with elements added in future versions of HTML.
  Once we've declared the component, we can use it in our template:
  [code]import Vue from 'vue' const vm = new Vue({ el: '#app', })5[/code]   The crucial part here is how I pass the data property down to the component:
  [code]import Vue from 'vue' const vm = new Vue({ el: '#app', })6[/code]   The colon at the start of that attribute is crucial; it tells Vue that the attribute we're passing down is dynamic and that the component should be updated every time the data changes. Vue will evaluate the value of githubData[currentUsername] and ensure that the GithubUserData component is kept up to date as the data changes.
   If you find :data a bit short and magical, you can also use the longer v-bind syntax:
  [code]import Vue from 'vue' const vm = new Vue({ el: '#app', })7[/code]  The two are equivalent, so use whichever you prefer.
  Conclusion

   With that, our Vue.js 2.0 GitHub application is in a pretty good state! You can find all the code on GitHub and even check out the application running online .
  I had high hopes when getting started with Vue, as I'd heard only good things, and I'm happy to say it really met my expectations. Working with Vue feels like taking the best parts of React and merging them with the best parts of Angular. Some of the directives (like v-if, v-else, v-model and so on) are really easy to get started with (and easier to immediately understand than doing conditionals in React's JSX syntax), but Vue's component system feels very similar to React's.
  You're encouraged to break your system down into small components and all in all I found it a very seamless experience. I also can't commend the Vue team highly enough for their documentation, it's absolutely brilliant. The guides are excellent and the API reference is thorough yet easy to navigate to find exactly what you're after.
   If you've enjoyed this post and would like to learn more the best place to start is definitely the official Vue.js site . If you're interested in some of the other Vue libraries - including Vuex for state management and the Vue router - keep an eye on the SitePoint's JavaScript channel, as I'll be continuing my Vue adventures in a future article!
   This article was peer reviewed by Vildan Softic . Thanks to all of SitePoint's peer reviewers for making SitePoint content the best it can be!
友荐云推荐




上一篇:五款顶级回归测试工具概述
下一篇:Pure CSS Horizontal Scrolling | CSS-Tricks
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

ΔΓΨΣΟΓ 发表于 6 天前
灌,是一种美德。
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表