最近接触的几个项目框架全部用到了Vue.js技术,没办法只能对vuejs进行深入学习,不过可喜的是Vue.js学习路线非常快,上手也是非常快的,所以对于前端开发也是主流的开发框架了。不过其中的js部分我还得抽时间去专门地学习,否则自己的前端知识非常不扎实。
下面预计还有几篇关于Vue,大多是页面渲染,部署运维等其他知识了,当然了,有时间还是以项目为主(Vue.js项目大多以微信小程序为主,到时候可以直接上手一波了)
目录
概述
随着网络的流行,很多的Wap(H5)应用也随之出现了,如微店、微站各个App中包含的H5页面。然而传统的技术特点:单击某个按钮或者提交表单Webpack会整体刷新,同时js/css请求往往很多(经常过百)。
所以越来越多的App采用SPA架构,如果项目要用在H5上面,那么一定要使用单页应用框架,例如Angular,React,Vue.js都是很好的框架。
主要的Web应用分为两类:传统的Web页面和单页应用(Single Page App)
传统的Web页面每次单击一个链接都会引起页面的整个刷新;
以CSDN为例:每次页面打开,页面中的.js,.css,图片文件等资源会加载一遍,可以看到左下角一共加载了237个请求,耗时0.545s.
一般的Web页面的例子,从第一行到最后一行,都要加载my.js,my.css外部资源。
<head>
<script src = "my.js" ></script>
<style src = "my.css" ></style>
<head>
单页应用精髓就是点击任何链接不会引起页面的整体刷新,只会通过Js替换页面的局部内容。
说到这里就不得不谈 Ajax(js的异步处理),由js发起一个Http异步处理,用户可以一边上下滚动页面一边等待这个请求来返回数据。
Vue.js 是一个MVVM(Model - View - ModelView) 的SPA框架。
官方文档地址: Vue官方文档
简单来说,学会了Vue.js 就学会了微信小程序和阿里巴巴的Weex。
用到Vue.js的项目:
滴滴出行,饿了么,Gitlab,新浪微博等
原生的Vue.js
所谓原生,就是独立的Vue.js ,不与Webpack等框架结合使用。
极速入门
本人使用Webstorm进行开发:
Vue.js安装非常简单,只要引入一个第三方的JS包即可。
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
下面来看一个简单的例子:
在头部引入Vue.js包。在body引入了一个div,可以认为所有的页面展示都是在div下面的,当我们做任何点击的时候整个页面不会刷新。
var 就是创建一个Vue对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<title>测试Vue</title>
</head>
<body>
<div id='app'>
{{ show_my_text }}
</div>
<script>
var app = new Vue({
//指定所有的代码操作,对于div id= ‘app’来操作的
e1 : 'app',
// data表示Vue.js管理的变量赋值
data : {
show_my_text : 'Vuejs is the best one!'
}
})
</script>
</body>
</html>
TODO-list项目
这个例子就是SPA的应用:
需求:1.可以列出待办事项,2.新建待办事项 3.可以把待办变成已办完。
这里的技术细节比较复杂,涉及到了组件,监听器,过滤器等。
<!DOCTYPE html>
<html>
<head>
<title>TodoMVC</title>
<!-- 引入vuejs库-->
<script src="https://unpkg.com/vue@2"></script>
<link
rel="stylesheet"
type="text/css"
href="https://unpkg.com/todomvc-app-css@2.2.0/index.css"
/>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<section class="todoapp">
<!-- 定义了header,包括文字的提示和输入框-->
<header class="header">
<h1>todos</h1>
<input
class="new-todo"
autofocus
autocomplete="off"
placeholder="What needs to be done?"
v-model="newTodo"
@keyup.enter="addTodo"
/>
</header>
<!-- 这里的代码把用户已经输入的待办事项做循环展示-->
<section class="main" v-show="todos.length" v-cloak>
<!-- 全选框-->
<input
id="toggle-all"
class="toggle-all"
type="checkbox"
v-model="allDone"
/>
<label for="toggle-all"></label>
<!-- v-for 用来循环-->
<ul class="todo-list">
<li
v-for="todo in filteredTodos"
class="todo"
:key="todo.id"
:class="{ completed: todo.completed, editing: todo == editedTodo }"
>
<div class="view">
<input class="toggle" type="checkbox" v-model="todo.completed" />
<label @dblclick="editTodo(todo)">{{ todo.title }}</label>
<button class="destroy" @click="removeTodo(todo)"></button>
</div>
<input
class="edit"
type="text"
v-model="todo.title"
v-todo-focus="todo == editedTodo"
@blur="doneEdit(todo)"
@keyup.enter="doneEdit(todo)"
@keyup.esc="cancelEdit(todo)"
/>
</li>
</ul>
</section>
<!-- 底部的状态,点击后可以进行过滤-->
<footer class="footer" v-show="todos.length" v-cloak>
<span class="todo-count">
<strong>{{ remaining }}</strong> {{ remaining | pluralize }} left
</span>
<ul class="filters">
<li>
<a href="#/all" :class="{ selected: visibility == 'all' }">All</a>
</li>
<li>
<a href="#/active" :class="{ selected: visibility == 'active' }"
>Active</a
>
</li>
<li>
<a
href="#/completed"
:class="{ selected: visibility == 'completed' }"
>Completed</a
>
</li>
</ul>
<button
class="clear-completed"
@click="removeCompleted"
v-show="todos.length > remaining"
>
Clear completed
</button>
</footer>
</section>
<footer class="info">
<p>Double-click to edit a todo</p>
<p>Written by <a href="http://evanyou.me">Evan You</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<!--js代码部分-->
<script>
// Full spec-compliant TodoMVC with localStorage persistence
// and hash-based routing in ~120 effective lines of JavaScript.
// localStorage persistence
// 下面的代码使用了浏览器的localStorage进行存储,同时定义了fetch()和save()用来方便操作
var STORAGE_KEY = "todos-vuejs-2.0";
var todoStorage = {
fetch: function() {
var todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]");
todos.forEach(function(todo, index) {
todo.id = index;
});
todoStorage.uid = todos.length;
return todos;
},
save: function(todos) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
}
};
//定义过滤器,分别对ative,completed和all进行过滤
// visibility filters
var filters = {
all: function(todos) {
return todos;
},
active: function(todos) {
return todos.filter(function(todo) {
return !todo.completed;
});
},
completed: function(todos) {
return todos.filter(function(todo) {
return todo.completed;
});
}
};
//定义的Vue的实例
// app Vue instance
var app = new Vue({
// app initial state
data: {
todos: todoStorage.fetch(),
newTodo: "",
editedTodo: null,
visibility: "all"
},
// watch todos change for localStorage persistence
watch: {
todos: {
handler: function(todos) {
todoStorage.save(todos);
},
deep: true
}
},
// computed properties
// http://v2.vuejs.org/guide/computed.html
computed: {
filteredTodos: function() {
return filters[this.visibility](this.todos);
},
remaining: function() {
return filters.active(this.todos).length;
},
allDone: {
get: function() {
return this.remaining === 0;
},
set: function(value) {
this.todos.forEach(function(todo) {
todo.completed = value;
});
}
}
},
filters: {
pluralize: function(n) {
return n === 1 ? "item" : "items";
}
},
//核心方法,用来实现对待办事项的增加、删除和修改
// methods that implement data logic.
// note there's no DOM manipulation here at all.
methods: {
addTodo: function() {
var value = this.newTodo && this.newTodo.trim();
if (!value) {
return;
}
this.todos.push({
id: todoStorage.uid++,
title: value,
completed: false
});
this.newTodo = "";
},
removeTodo: function(todo) {
this.todos.splice(this.todos.indexOf(todo), 1);
},
editTodo: function(todo) {
this.beforeEditCache = todo.title;
this.editedTodo = todo;
},
doneEdit: function(todo) {
if (!this.editedTodo) {
return;
}
this.editedTodo = null;
todo.title = todo.title.trim();
if (!todo.title) {
this.removeTodo(todo);
}
},
cancelEdit: function(todo) {
this.editedTodo = null;
todo.title = this.beforeEditCache;
},
removeCompleted: function() {
this.todos = filters.active(this.todos);
}
},
// a custom directive to wait for the DOM to be updated
// before focusing on the input field.
// http://v2.vuejs.org/guide/custom-directive.html
directives: {
"todo-focus": function(el, binding) {
if (binding.value) {
el.focus();
}
}
}
});
// handle routing
function onHashChange() {
var visibility = window.location.hash.replace(/#\/?/, "");
if (filters[visibility]) {
app.visibility = visibility;
} else {
window.location.hash = "";
app.visibility = "all";
}
}
window.addEventListener("hashchange", onHashChange);
onHashChange();
// mount
app.$mount(".todoapp");
</script>
</body>
</html>
样式图:
Webpack+Vue.js开发
NVM,NPM,Node
nvm(node version是非常好用的Node版本管理器,如果node版本不对,运行起来会有各种问题。
下载地址:NVM-windows
设置环境变量:
NVM_HOME: D:\nvm
NVM_SYMLINK : C:Program Files\nodejs
windows查看列出的的安装node版本:
列出本地安装的版本
安装的时候只要选择一个版本就可以,例如:
nvm install 17.5.0
加快nvm和npm的下载速度,修改成国内的镜像服务器:
对于nvm来说
NVM_NODEJS_ORG_MIRROR = https://npm.taobao.org/dist nvm install
对于npm,使用cnpm来代替npm
npm install - g cnpm --registry=https://registry.npm.taobao.org
然后通过国内的淘宝服务器安装node包:
Webpack
随着SPA单页应用的发展,使用js/css/png等文件特别多,比较难管理,文件夹结构也容易混乱,希望项目可以具有压缩的功能。
Webpack是一个打包工具,可以把js,css,node module,coffeescrip,scss等打包在一起,简直是SPA的福音。这样做可以做到路由的分离以及快速打包、部署以及项目上线。
安装Webpack:
npm install --save-dev webpack
因为Webpack自身支持Vue.js,所以Webpack与Vue.js很难分清谁是谁了。
开发环境的搭建
同时安装vue和vue-cli 这两个node package,-g表示可以被全局使用。
npm install vue vue-cli -g
可能会遇到这样的错误:npm WARN deprecated har-validator@5.1.5: this library is no longer supported
原因是资源的问题,要配置淘宝镜像
npm config set registry https://registry.npm.taobao.org
配置完成后检验是否成功
npm config get registry
如果下载后还是报错,那就是包问题,解决方法是删除文件的package-lock文件,重新npm install就可以了。
创建一个项目
vue init webpack my-project
会发现’vue’ 不是内部或外部命令,也不是可运行的程序或批处理文件。
首先进入npm查看全局安装路径:
进入到页面后,确实发现有vue了。
进入到环境变量:
重新打开cmd,此时安装完成了。
下面就进入到刚才的vue install一步:
vue init webpack my-project
安装依赖:
cd my-project
npm install
在本地以默认端口运行:
npm run dev
打开localhost:8080就可以看到创建的欢迎页了。
Webpack下的Vue.js项目结构
会生成一个崭新的项目,
在build文件中保留了各种打包脚本,不可随意更改。
config文件是与部署和配置相关的,在index.js定义了开发的端口,图片文件夹和代理服务器等
dist文件夹:对应的css,js,map都在这里。有了map文件夹浏览器可以下载整个.js文件。
在node_modules文件中,第三方包特别多,所有在package.json中定义的第三方包都会被自动下载。
src文件,是核心源代码所在目录。assets是放的图片,components用到的视图和组件(核心),router/index.js是路由文件,对应了各个页面的对应的Url.
Webpack+Vue.js入门
注意这里的位置是用小写,如果用大写将不能运行。
当然了你可以直接打开刚才创建的文件就可以,在readme直接运行npm run dev就可以了。
创建一个页面
默认的路由文件是src/router/index.js:
下面建一个sayhi,注意@表示当前目录
import Vue from 'vue'
import Router from 'vue-router'
// import HelloWorld from '@/components/HelloWorld'
//引入SayHi 这个component
import SayHi from '@/components/SayHi'
Vue.use(Router)
export default new Router({
routes: [
// 定义了/#/say_hi这个url
{
path: '/say_hi',
name: 'SayHi', // Vue.js内部使用的名字
component: SayHi //对应的.vue页面的名字
}
]
})
创建一个新的Componet:
src/components/SayHi.vue
<template>
<div>
Hi Vue
</div>
</template>
<script>
export default {
data () {
return { }
}
}
</script>
<style scoped>
</style>
总是报 Expected indentation of 2 spaces but found 4错误,深入发现是缩进的原因,这个问题的原因在于eslint的风格样式缩进检测,eslint给出的规则是2个缩进,但我们通常是4个缩进。
在上面的代码中,template表示的是html模板,是最普通的HTML,script是js代码,所有的js代码都放在这里,这里使用的是EMScript,style表示所有的css文件都可以放在这里。
运行就可以了。
当然了可以增加样式:
SayHi.vue
<div class ="hi">
<style scoped>
.hi {
color: red;
font-size: 20px;
}
</style>
定义并显示变量:
可以在data中定义:
export default {
data () {
return {
message: '你好Vue'
}
}
}
当然了需要引用哦,这样就可以显示了:
<div class="hi">
Hi Vue
{{ message }}
</div>
Vue.js的ECMScript
我们使用的不是原生的js,而是新语言ECMScript(关于js我将会单独做几篇博客)
常量与变量:
声明本地变量:
var : 有可能引起变量提升,或者块级作用域问题
let : 为了解决以上两个问题。
多用let ,少用var
常量:
const title = “123”
全局变量:
window.title = “123”;
导入代码: import,用于导入外部代码:
import Vue from 'vue'
import Rounter from 'vue-router'
在每个vue文件的script中,都存在exprt default{…} 代码,作用是方便其他代码对这个代码进行引用。
其实在之前的代码我们发现:
export default {
//等同于 data ()
data: function() {
return {}
}
}
分号可以省略。
以上。