关于 Vue
由于要去了解新的业务系统,还有就是要滚回去写 Android 了,这里就做一下小结吧。
感觉相对于 React 来说,Vue 使用起来更加有写前端的感觉,上手也比较快,经过一两天的摸索就大概知道要怎么写了。
相同点:
- 都使用了 虚拟Dom 的技术,来提高渲染的性能和效率。
- 都是 MVVM 的架构设计。
- 组件化明显
- 单向数据流。
不同点:
- React 使用的是 JSX ,Vue 使用更多是 template 。
- React 的门槛更高, Vue 的门槛低一些,甚至直接导入 js 文件就可以开始怼了。
练习
通过这几天的学习,也掌握了一些其他的东西,也在这里一并讲一下吧。
这个练习是仿照 豆瓣电影 的首页来做的。效果如下
跨域的问题
第一个遇到的问题是跨域,一开始使用 Vue 的时候是通过导入 js 文件来写的。网络请求用的是 ajax ,使用 jsonp 就可以轻松解决跨域的问题( jsonp 只能使用 GET 请求)
在后面学到单文件的时候,问题就不一样了。因为使用单文件,就需要使用构建工具进行预处理和构建,使用到了 webpack ,而且本地还跑起来了 node 服务,用于热更新等操作。
像 Vue 这种 MVVM 架构的框架,我就不打算使用 jq 了,也不打算使用 ajax 了。
网络请求这块使用的是 axios ,这是一个基于 promise 的网络请求库。
关于跨域的问题,其实对于现在 前后端分离的开发模式,早已有了解决方案,我使用的是 node 的代理转发来解决这个问题。
其实原理是通过 node 做了一个请求的代理转发,本地发请求用的是另一个映射的地址,这个请求会被 node 转化成真正的请求地址并发送出去。
具体的步骤如下:(使用的是官方的脚手架搭建的项目)
- 在 config 目录下,找到 index.js 文件。
- 找到
proxyTable
这个配置,这个其实就是代理的配置,往里面加入如下配置(这个代理可以配置多个,像我使用到的豆瓣的接口有两种类型,我也是配置了两个代理):
'/api': {
target: 'http://api.douban.com', //设置你调用的接口域名和端口号.别忘了加http
changeOrigin: true, //允许跨域
pathRewrite: {
'^/api': ''
// '/'这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替。比如我要调用'http://api.douban.com/v2/movie/top250',直接写‘/api/v2/movie/top250’即可
}
- 当使用到这个地址发请求的时候就使用配置的代理前缀就可以了,就像
/api/v2/movie/nowplaying?apikey=xxx
这样就可以了。
关于 webpack
其实在这个时候,还看了挺多的关于 webpack 的内容,但是然并卵,直接官方的脚手架就可以直接搭起项目了,还有 热更新,route 等等等,真是美滋滋,哈哈哈。
webpack 是我接触过的第一个前端打包构建工具,之前就是直接写原生 html + css + js ,根本没有用过这个东西,也不知道还有这种东西,虽然之前有写过 react native 但是没有注意到这个东西。
webpack 的意义
就如官网所显示的,webpack 最重要的功能就是打包,可以把几乎所有的资源都打包在一起,减少体积和网络请求次数。
我觉得 webpack 更加重要的功能是 预处理 。(当然,官网上说的 “打包” 也有预处理的意思)webpack 支持使用 loader 和 插件 来对资源进行预处理,和构建,这样就有很多的可能性了。这样我们就可以自己定义代码的规则和风格了。
比如:
- 扩展格式支持。 像 Scss , TypeScript 等这些无法直接给浏览器解析的格式,通过 响应的 loader 就可以转化成 浏览器能够支持的 css 和 JavaScript 了。Vue 的单文件也是一个例子。
- 兼容处理。 还有 es6 等比较先进的语法,有些旧的浏览器还是不支持的,使用 webpack 打包的时候也可以转化成 es5 的语法。
这样一处理,开发者就在写代码的时候就可以省很多力气了。和以前相比简直就是爽的飞起了。
其他具体的用法这里就不详说了,因为我们今天的重点内容不是这个!(认真脸)(其实是因为我忘得差不多了。。。。。)
Vue 单文件
一开始也是没有注意到有这个东西,但是越写越觉得不对劲。这么多东西(模板,js,css)都写在一起,或者拆开写,需要的时候再组合到一起。这么写还是太麻烦了。要不就不够解耦,或者不够内聚。
Vue 单文件就横空出世了!!!
Vue 单文件是后缀为 .vue 格式的文件。
主要分为三个部分:
Template
:模板
script
:js,其实主要就是 export vue 对象
style
: css,如果配置了 scoped
就只有在当前组件中生效。这里还支持 scss
等扩展语法。需要在 webpack 里面配置 sass-loader
和 node-sass
这两个 loader,在 style 配置 lang="scss
就行了。
关于 scss
这个也是一个好东西呀。使 css 也具有一部分程序的功能,支持 变量、嵌套、继承等。写起来也是舒服很多。
关于官方的 cli
项目结构大概如下:
忽略掉一些不重要的东西后,大概是这个样子:
|- build (编译配置,webpack配置)
|- config (项目配置)
|- src
|- assets (资源文件夹)
|- compoments (组件)
|- App.vue (根组件)
|- main.js (构建的入口)
|- index.html (html 的入口)
先看一下 index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>test</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
很简单,body 里面就是一个div ,id 为 app。再看一下 main.js
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router, //相当于 router:router ,配置路由
components: { App },
template: '<App/>'
})
这个也很简单,APP 组件 挂载到 #app 上面,然后把 .router
路由也挂载进来,就做了这两件事。接下来我们看一下 APP 这个组件吧。
<template>
<div id="app">
<img src="./assets/logo.png">
<router-view/><!-- 路由出口 -->
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
模板里面直接就是一个 img 加 路由 就没了,我们再回过头看一下 路由 吧,在 .router
文件夹的 index.js
文件
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})
这里路由只配置了 一个地址 ,就是根地址,使用的组件是 HelloWorld,那我们再看一下这个 组件
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
<ul>
<li>
<a
href="https://vuejs.org"
target="_blank"
>
Core Docs
</a>
</li>
<li>
<a
href="https://forum.vuejs.org"
target="_blank"
>
Forum
</a>
</li>
<li>
<a
href="https://chat.vuejs.org"
target="_blank"
>
Community Chat
</a>
</li>
<li>
<a
href="https://twitter.com/vuejs"
target="_blank"
>
Twitter
</a>
</li>
<br>
<li>
<a
href="http://vuejs-templates.github.io/webpack/"
target="_blank"
>
Docs for This Template
</a>
</li>
</ul>
<h2>Ecosystem</h2>
<ul>
<li>
<a
href="http://router.vuejs.org/"
target="_blank"
>
vue-router
</a>
</li>
<li>
<a
href="http://vuex.vuejs.org/"
target="_blank"
>
vuex
</a>
</li>
<li>
<a
href="http://vue-loader.vuejs.org/"
target="_blank"
>
vue-loader
</a>
</li>
<li>
<a
href="https://github.com/vuejs/awesome-vue"
target="_blank"
>
awesome-vue
</a>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
这个也没什么好说的,就是渲染了一个界面。但是到这里,我们就大概明白了这个结构是怎么回事了。
后面我们要修改的时候,一般就是把 路由里面的 /
路径的映射换成我们的组件就可以了。
Vue 基础
终于说到 vue 的基础了,前排的同学要睡着了。
先看图!
官方的文档中,赫然写着说 我们不是完全遵循 MVVM 模型! 但是对于我这种小菜鸡来说,我现在看到的还就是 MVVM ,而且大部分情况也确实是 MVVM 。我们开发不需要管数据怎么跟视图绑定,我们只要管理好数据就可以了,其他的交给框架去做!
data
这个就是 Vue 的数据,只要是放在这里面的数据更新了,视图里面引用到的相应数据就会更新并且重新渲染。
我们可以直接这么写
var vm = new Vue{
data : {
abc: 'abc'
}
}
这样就创建了一个 Vue 实例。当然关这样写是没有用到,vue 还没有挂载到 DOM 节点上,我们还需要这样
<html>
<body>
<div id="app">
<p>{{abc}}</p>
</div>
</body>
</html>
var vm = new Vue{
data : {
el : '#app'
abc: 'abc'
}
}
后面,我们修改数据的时候,直接vm.abc='def'
页面中的显示的 abc
就会变成 def
这就完了。
要注意的是在 .vue 里面,data 是要返回一个函数。
还是推荐使用 .vue 单文件
但是,很多时候我们不会直接把 要加载的 vue 视图放到 DOM 里面去,而且通过 template
,因为 template
不会直接被加载出来。
或者,直接使用 vue 文件来写更加痛快,骚年,不要挣扎了,跟我走吧。
其实 vue-loader 把 .vue 中的 template 节点,用 render 函数把视图渲染出来的。
怎么写?
那些 if else
,for
,bind
,on
这些东西就不讲了,也没什么好讲的,看一下官方文档就很舒服了。
其实写 vue 跟写原生的 html 和前端最不一样的就是思维要转变过来,转变过来之后,思路就很清晰了。尽量不要去操作 DOM 元素!交给 Vue 去做。
就说一下用的比较多的几个东西吧。(说的这几个东西都是在 .vue 中的 export 的对象的属性)
components : 导入其他的组件,使用的时候要在里面声明。之前想要在一个 组件里面引用另一个组件,真的是不知道怎么弄,通过 import 进来了也没用,需要在这里注册一下。
mounted:这个是生命周期的一个钩子,还有其他一些钩子,会在 vue 实例挂载上去后调用,我一般会在这里做网络请求或者,一些初始化的工作。
methods:methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为 Vue 实例。而且文档中也说明,不要用箭头函数,否则会报 undefined。一开始的时候,本来是使用 computed
的,但是不能传参,不好用。
watch:感觉这个东西就很厉害了,可以监控数据的变化。这样我们就只要触发一个事件,就可以唤起整个事件流了,就像多米诺骨牌一样。但是别滥用。
还有,有些时候需要使用箭头函数来使 this 对象指向 vue 实例,这样方便我们操作。比如像 setInterval
,promise
等。
在操作 data 里面的数组的时候,直接 array[2]='222'
, 这样是不会触发更新的。但是可以通过 push()
,pop()
等这些方法是会触发更新的,感觉有点像 java 中的指针引用原理一样。