Vue.js 是一个MVVM的架构
视图View中数据发生变化,观察者会改动Model中JS的数据;反之亦然。
实现了数据的双向绑定。
是为了避免经常刷新整个网页资源而应运而生的(主要用ajax交互)
数据驱动
即是只要JS的数据改变,Vue.js观察者的Directives就会发现,并且自动让DOM中的数据跟着改变。如下图。
该图的红色是从右到左传递的。
同样,view中的数据改变了,Vue.js也能够让Model中的JS对象自动跟着转变。
该图的红色是从左到右传递的。
具体的原理如下。
从数据改变到更新视图的过程:
有一个watcher在观察Model中的a.b对象,只要在JS中调用了a.b,都会在View中用v-text更新一个a.b的值。
Vue.js的介绍到此结束。
Vue CLI
CLI中启动的方式:
1. 打开命令行CLI(node.js的或者cmd等都可以)
2. cd到当前vue项目的主文件夹(即包含有package.json的根目录)
3. 执行 npm run dev 即可,启动当前vue项目在node.js上运行(配置相关内容在config/index.js)。
文件结构分析
文件夹
build和config都是webpack配置相关
node_modules是通过npm install安装的依赖代码库
src是存放源码目录
static是存放第三方静态资源的,static里面有一个.gitkeep文件,表示即使文件夹为空也要把它上传到git仓库里(默认是不上传空文件的)。
文件
.babelrc是用于把ES6转换为ES5的一些配置,在相关依赖里能够看到一些转换的plugin。
.editorconfig是编辑器的一些配置
.eslintignore是忽略语法检查的文件目录
.eslintrc.js是eslint的配置文件,核定语法检查的规则
.gitignore让git仓库去忽略该目录中的文件
index.html是入口html文件,内容十分简单,但以后项目编译时会把所有的vue.js生成的结构都插入到html文件中。
package.json是项目的配置文件,描述我们这个vue项目的信息、依赖。
README.md就是一些关于项目如何使用的文本信息。
上面说了入口html是index.html,而入口js则是main.js
main.js引入了两个库,一个是vue提供的,另外一个是当前项目App.vue文件的
new Vue实例化一个Vue实例
el是一个挂载点,挂在了body这个DOM
components是一个注册了一个当前App的插件(依赖了App.vue)
对于App.vue
分为了三个组件,template(html代码),script(js代码)和style(css代码)
其中在template中有<Hello>的标签,它必须要包含进去才可以。
关于路由,用路由的一个最大的好处就是能够热加载Hello.vue中的信息,从而不需要重启整个项目。
关于export default
实际上是一个语法糖,能够把当前script中export的内容在另外一个vue的script中通过import...from ”XX“ 获取。
整个程序编写逻辑
首先要知道,根节点出口是App.vue和main.js,所有的components和router都需要在这里体现出来。
然后我们可以在main.js中处理这个import其他文件的关系。
components包含每一个小grip方框的内容,router指定所有组件component基于主页面的映射关系。
打包之后请求的文件
webpack产生的主要的是三个文件:
localhost就是主页面;
app.js是打包后的vue代码(包含js和css),并且有很多解释ES6语法的代码,所以大小能达到1M;
websocket是访问的方式,RESTful
要注意的是,源文件中并不存在app.js,html文件也是没有引入任何资源。产生这一切的原因就是使用了webpack编译。
Webpack配置
打包就是能够将各种各样的前端资源以及其依赖全部整合为.js文件(.css)+.png文件等静态资源,便于部署。
只对开发时webpack,运行时webpack这里暂时不涉及
首先,从其入口,在package.json的npm dev代码开始分析。
可以看到,在json的“scripts”中有这样的内容:
{
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"lint": "eslint --ext .js,.vue src",
"build": "node build/build.js"
},
"dependencies": {
"vue": "^2.5.2",
"vue-router": "^3.0.1"
}
}
上面表示了,执行npm dev实际上是执行了webpack-dev-server --inline --progress --config build/webpack.dev.conf.js这样一长串代码的。它表示是开发时的一些配置,运行的build/webpack.dev.conf.js这个文件可以在目录中找到。
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
创建首先是引入了各种依赖,path指的是node.js提供的一个api,它是表示提供一些文件路径、操作一些方法。
webpack是一个node.js的API,不仅仅可以全局调用,也可以在node中通过api引用。
config是一个配置文件,能够配置开发时、运行时的一些属性。
merge用来合并配置文件,有点类似工具方法。
baseWebpackConfig是运行时、开发时共享的配置文件。
HtmlWebpackPlugin是webpack提供操作html的插件。
**webpack.base.conf.js **
指定了webpack编译的入口js文件main.js
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
...
}
config/index.js,使用配置的入口
基本上/build/中所有的文件都需要依赖这个index.js来获取相关的配置(比如说port=8080)
config.dev.ProxyTable,哪些接口需要转发,在这里配置一下就好了
devMiddleware,中间件
实际上是很强大的,它是express()专门为了webpack专门开发的一个中间件。
细心的人会发现,我们虽然最终产生了html、app.js等生成出来的文件,但是在项目文件目录中,并没有看到这些生成的文件。那是因为,中间件做了一些事情——编译好的文件实际上是存放在了内存里。因此我们在页面中访问的资讯实际上都是在对内存作访问,这样看来中间件的功能是非常强大的!
** 用IcoMoon.io网站来处理图标字体制作
src里面的结构
会有一个main.js的入口js文件,App.vue是整个页面的vue实例文件,可以把整个页面看成是vue的大组件。
三个子目录,assets存放静态资源,components存放组件文件(通常要再创建一个子包来存放每一个Vue),router存放路由配置文件。
子包的目的是为了存放一些其他的资源文件,比如图片,以满足Vue.js资源就近维护的原则。
另外,在根目录会存在一个common的文件夹,存放一些公用的js,fonts和stylus(一个css预处理器)。
mock数据
在当前前后端分离的代码设计中,主要交流手段是通过Ajax请求来获取数据。
在实现前后端分离,前端有一个很重要的做法,就是数据的mock:即模拟一些假的数据。
** 新版Vue.js中不存在dev-server.js了(它被整合在了webpack.dev.conf.js中去了)
因此我们要改变的应该是webpack.dev.conf.js,根据这里。
//第一步,在const portfinder = require(‘portfinder’)后添加
const express = require('express')
const app = express()//请求server
var appData = require('../data.json')//加载本地数据文件
var seller = appData.seller//获取对应的本地数据
var goods = appData.goods
var ratings = appData.ratings
var apiRoutes = express.Router()
app.use('/api', apiRoutes)//通过路由请求数据
//第二步找到devServer,在里面添加
before(app) {
app.get('/api/seller', (req, res) => {
res.json({
errno: 0,
data: seller
})//接口返回json数据,上面配置的数据seller就赋值给data请求后调用
}),
app.get('/api/goods', (req, res) => {
res.json({
errno: 0,
data: goods
})
}),
app.get('/api/ratings', (req, res) => {
res.json({
errno: 0,
data: ratings
})
})
}
路由器的作用
路由器一个很重要的作用就是改变哈希(URL),点击之后,头上的url会发生变化,并且切换到别的component去,这是路由器的功劳。
CSS编写规范
1. 先写display布局、position定位,写在最前
2. 再写宽高,触发重绘的,不可继承的属性
3. 最后写字体、颜色,可被集成的属性
一个自己找了很久的bug
下面文件为header/header.vue
<script>
export default{
props: ['seller'],
methods: {
showDetail() {
this.detailShow = true;
},
hideDetail() {
this.detailShow = false;
}
},
created() {
this.classMap = ['decrease', 'discount', 'special', 'invoice', 'guarantee'];
},
components: {
// SupportIco
}
};
</script>
这里的问题在于,我把props打成了proprs,结果导致渲染不出来,header.vue一直无法显示。F12审查也是只能看到一行注释,没找到任何关于header的内容。
用v-show变量控制是否显示detail页
<div class="detail" v-show="detailShow">
<div class="detail-wrapper">
……
</div>
<div class="detail-close" @click="showDetail(false)">
<span class="icon-close"></span>
</div>
</div>
我们在.detail中使用了detailShow这个变量来判断是否展示这个div
export default{
props: ['seller'],
data() {
return {
detailShow: false
};
},
methods {
showDetail(isShow){
this.detailShow = isShow; // 因为data和methods间有依赖跟踪,能够访问到detailShow
}
},
...
}
并且在data()定义这个变量默认为false,即当这个vue实例化的时候,我们会返回一个这样的datailShow变量,方便后续是否展示页面的判断。
*** data() { return { ... }; } 这个属性能够对数据进行绑定,为这个数据添加getter、setter,方便别的vue使用。
通过vue,我们只需要在export default中写出相关处理的数据、方法就可以直接在HTML标签中使用的。
在整个”点击按钮-出现详情页-点击叉叉-详情页关闭“的过程中,不需要像以前一样进行DOM的操作,大大减少代码量。这个就是Vue最大的好处。
一些CSS的知识点
- CSS中.clearfix这个类是用来清除浮动的。
- CSS中,flex属性只有三个参数,分表表示:是否等分(0、1),是否缩放(0、1),占位的空间(... px)
- CSS中加样式,要多用class,少用标签。因为标签涉及多层嵌套,效率比较低。
- 重大的CSS/Stylus注意事项:HTML想要添加样式的那个标签,**必须在stylus中处于同样的层级结构的位置!**否则,不会被上样式,在渲染出来的页面该标签(如span)的样式就只能出现一片空白。
举个例子,比如你是在<div class="a">中的<span class="icon">,那么你在stylus中必须得让.icon在.a的子属性里。
虽然说起来很简单,但是因为stylus的缩进太容易搞错,很容易导致隐晦的bug,从而样式也得不到渲染。
- 在main.js中引入import '../static/css/reset.css' (这个css文件是要自己写的,网上有)能够重置一些默认标签(比如ul/li)等的系统自带样式。重置了样式就能够按照自己的样式编写正确运行,否则会出现奇怪的显示效果。