什么是vue
作者:Evan You(尤雨溪),学过点艺术,偶尔做设计,主要写代码。曾经在 Meteor 和 Google 打过工。,在使用angular之后,提取Angular中为自己所喜欢的部分,构建出一款相当轻量的框架--vue.js;
初始版本 2014年2月,3年前; 稳定版本 2.5.9(2017年11月28日,14天前)
文件大小 76 KB 生产版 240 KB
16 KB 核心库 Vue、vue-router和vuex三个(都是 2.0 版本)加起来是26KB
Vue.js是一款流行的JavaScript前端框架,旨在更好地组织与简化Web开发。Vue所关注的核心是MVC模式中的视图层,同时,它也能方便地获取数据更新,并通过组件内部特定的方法实现视图与模型的交互。--维基百科的介绍
框架目前市场影响力:2016年一项针对JavaScript的调查表明,Vue有着89%的开发者满意度。 在GitHub上,该项目平均每天能收获95颗星,为Github有史以来星标数第10多的项目。
Vue.js (读音 /vjuː/,类似于 view) 是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计=== 官方介绍
''
关于渐进式和自底向上增量开发:
知乎有篇文章:https://www.zhihu.com/question/51907207
高赞的是徐飞的观点:主张最少,用户使用可变性场景较多,经常会因为框架的主张而造成不便,比较形象的是第二个回答:
它给你提供足够的optional,但并不主张很多required,给你一座空房子,你所需要的东西是可选的,不会说必须要,选择空间较大
对于vue来说,大家都觉得有几个学习阶段:
- 每个阶段的vue框架的依赖程度和使用的场景来说也是不同的,声明式渲染和组建系统是Vue的核心库所包含内容,而客户端路由、状态管理、构建工具都有专门解决方案
- 我之前的毕设采用的便是声明式渲染和组建系统和客户端路由这三种,构建工具也只是搭建了一个框架而已,对于状态管理就没有使用到。
vue简单使用 -- 不使用构建工具的时候
正常使用,上代码
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<p>{{count}}
<button @click="inc">+</button>
<button @click="dec">-</button>
</p>
</div>
<script>
new Vue({
el:'#app',
data () {
return {
count: 0
}
},
methods: {
inc () {
this.count++
},
dec () {
this.count--
}
}
})
</script>
- 一个正常的调用,一个div使用,js采用vue实例的方式来讲述数据变化的故事
跟正常的原生js和jquery相比较
- 原生js
<div id="app">
<p><span id="count">0</span>
<button id="inc">+</button>
<button id="dec">-</button>
</p>
</div>
<script>
var counter = document.getElementById('count');
var btn1 = document.getElementById('inc');
var btn2 = document.getElementById('dec');
var count = 0;
btn1.addEventListener('click',function (){
counter.innerHTML = ++count;
}
)
btn2.addEventListener('click',function (){
counter.innerHTML = --count;
}
)
</script>
代码行数倒是不算多,但是看起来的感受是:
使用了多个DOM API(getElementById,innerHTML)
DOM API设计的复合词太长
偏爱简洁的代码,而使用DOM API就构成了一种代码的臭味。
jquery
<script
src="https://code.jquery.com/jquery-3.1.1.js"
integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA="
crossorigin="anonymous"></script>
<div id="app">
<p><span id="count">0</span>
<button id="inc">+</button>
<button id="dec">-</button>
</p>
</div>
<script>
var count = 0
$('#inc').click(function(){
$("#count").html(++count)
})
$('#dec').click(function(){
$("#count").html(--count)
})
</script>
- jquery的选择器比起原生的更好,即使和querySelector相比也更简洁
- 使用精简的API替代Vanilla的。比如.html()比起.getElementById()来说,是要看着舒服点的
- 然而,内核基本不变:依然是添加EventListener,命令式的取值和修改值,依然你得懂得DOM的节点选择、事件监听、回调函数等
回过头说一说vue的优点
-
第一感觉就是:
- 规整。数据(data),方法(methods)放置的工工整整,一目了然。它充分的利用js的字面量对象的语法
- 整个应用接口设计,基本上采用的都是简单。一眼看过去,一个复合词也没有(比如getElementById就是4个复合词)
-
好处是:
- 现在,你不需要挂接EventListener,使用@click语法自动绑定事件,使用{{}}自动绑定数据
- 你不需要DOM的一系列的知识就可以构造此程序;对初学者来说,这个门槛真是降低太多
-
Vue.js的优美和简约,来源于声明式编程的理念。就是说我不需要通过一系列的函数调用来完成一件事儿,而是直接声明想要什么事儿。比如:
- 程序员直接声明{{count}},告诉Vue,此处使用Vue实例中的data对象内的count属性来填充。而不是调用.getElementById,.textContent来设置。
- 程序员通过@click直接声明点击事件指向位置为Vue实例内对象methods对应的方法。而不是通过调用.addEventListener,传入回调函数的方式来实现事件监听
整个Vue.js的应用接口设计的非常优美,但是能量巨大,做到这一点需要很多功力。这就是我佩服的设计哲学。把麻烦留给自己,让开发者感受简洁
vue几点思想:组件、生命周期、虚拟DOM
- MVVM
- 虚拟DOM
- 生命周期
vue几个过程的具体实现
声明式渲染
遵循原则:MVVM(Model-View-ViewModel)(我们看到的结果)
-
-在ViewModel当中会有一个叫Binder,或者是Data-binding engine的东西。以前全部由Presenter负责的View和Model之间数据同步操作交由给Binder处理。你只需要在View的模版语法当中,指令式地声明View上的显示的内容是和Model的哪一块数据绑定的。当ViewModel对进行Model更新的时候,Binder会自动把数据更新到View上去,当用户对View进行操作(例如表单输入),Binder也会自动把数据更新到Model上去。
- 例子
-
https://github.com/livoras/MVW-demos/blob/master/src/mvvm.html
如下图所示,Vue的依赖追踪通过ES5的 Object.defineProperty(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) 方法实现。比如,我们给它一个原生对象,Vue会遍历这个数据对象的属性,然后进行属性转换。每一个属性会被转换为一个 getter 和一个 setter。同时每个组件会有一个对应的 watcher 对象,这个对象的职责就是在当前组件被渲染的时候,记录数据上面的哪些属性被用到了。
例如,在渲染函数里面用到A.B的时候,这个就会触发对应的 getter。整个渲染流程具体要点如下:
当某个数据属性被用到时,触发 getter,这个属性就会被作为依赖被 watcher 记录下来。
整个函数被渲染完的时候,每一个被用到的数据属性都会被记录。
相应的数据变动时,例如给它一个新的值,就会触发 setter,通知数据对象对应数据有变化。
此时会通知对应的组件,其数据依赖有所改动,需要重新渲染。
对应的组件再次调动渲染函数,生成 Virtual DOM,实现 DOM 更新。
这样一个流程跟主流的一些框架,例如React是有较大区别的。在React中,当组件复杂的时候需要用 shouldComponentUpdate 做优化。但是,它也有自己的各种坑,比如要确保该组件下面的组件不依赖外部的状态。虽说这在大部分情况下是够用的,但遇到极大复杂度的应用,遇到性能瓶颈的时候,这个流程优化起来也是相当复杂的一个话题。
如下图所示,在Vue里面由于依赖追踪系统的存在,当任意数据变动的时,Vue的每一个组件都精确地知道自己是否需要重绘,所以并不需要手动优化。用Vue渲染这些组件的时候,数据变了,对应的组件基本上去除了手动优化的必要性。
<!doctype html>
<html ng-app="todoApp">
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="stylesheet" type="text/css" href="styles/style.css">
</head>
<body>
<div id="app">
<h1>TodosList Demo</h1>
<div>
<input type="text" class="input-todo" v-model="newTodoContent">
<button class="new-todo-btn" v-on="click: addNewTodo">新增</button>
</div>
<ul>
<li v-repeat="todos" v-class="done: done" v-on="click: checkTodo($index)">
{{content}}
</li>
</ul>
</div>
<script>
var ViewModel = require("vue")
var app = new ViewModel({
el: "#app",
data: {
newTodoContent: "",
todos: [{
content: "Make PPT!",
done: false
}]
},
methods: {
addNewTodo: function() {
if (!this.newTodoContent.length) return
this.todos.push({
content: this.newTodoContent,
done: false
})
this.newTodoContent = ""
},
checkTodo: function(i) {
var todo = this.todos[i]
todo.done = !todo.done
}
}
})
</script>
</body>
</html>
函数渲染与模板渲染
模板渲染:例如
<span>Message: {{ msg }}</span>
- 在单文件组件(.vue)
<template>
</template>
函数渲染
- 使用JSX函数渲染(HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法)
- 比较:模板更贴近我们的HTML,可以让我们更直观地思考语义结构,更好地结合CSS的书写。JSX和直接渲染函数,因为是真正的JavaScript,拥有这个语言本身的所有的能力,可以进行复杂的逻辑判断,进行选择性的返回最终要返回的DOM结构,能够实现一些在模板的语法限制下,很难做到的一些事情。
- 在绝大部分情况下使用模板,但是在需要复杂逻辑的情况下,使用渲染函数。在Vue2.0的路由和内部的一些实践上,都大量地应用渲染函数做复杂的抽象组件,
引入了虚拟DOM- 2.png
- Vue的编译器在编译模板之后,会把这些模板编译成一个渲染函数。而函数被调用的时候就会渲染并且返回一个虚拟DOM的树。这个树非常轻量,它的职责就是描述当前界面所应处的状态。当我们有了这个虚拟的树之后,再交给一个patch函数,负责把这些虚拟DOM真正施加到真实的DOM上。在这个过程中,Vue有自身的响应式系统来侦测在渲染过程中所依赖到的数据来源。在渲染过程中,侦测到的数据来源之后,之后就可以精确感知数据源的变动。到时候就可以根据需要重新进行渲染。当重新进行渲染之后,会生成一个新的树,将新树与旧树进行对比,就可以最终得出应施加到真实DOM上的改动。最后再通过patch函数施加改动。
- 这样做的主要原因是,在浏览器当中,JavaScript的运算在现代的引擎中非常快,但DOM本身是非常缓慢的东西。当你调用原生DOM API的时候,浏览器需要在JavaScript引擎的语境下去接触原生的DOM的实现,这个过程有相当的性能损耗。所以,本质的考量是,要把耗费时间的操作尽量放在纯粹的计算中去做,保证最后计算出来的需要实际接触真实DOM的操作是最少的。
组件系统
单向数据流
-
在Vue中,父子组件之间的通信是通过 props 传递。从父向子单向传递;而如果子组件想要在父组件作用里面产生副作用,就需要去派发事件。这样就形成一个基本的父子通信模式,在涉及大规模状态管理的时候会有额外的方案,这个后面会提到。
单文件组件
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
</div>
</template>
<script>
export default {
name: 'hello',
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基本解决方案--router.vuejs.org (vue-router 库)
状态管理
- 图中的这三个东西是一个单向数据流,State 驱动 View 的渲染,而用户对 View 进行操作产生 Action,会使State产生变化,从而导致 View 重新渲染。
- 单个的组件就是这样的,父子组件之间也会有这样的状态变化
-
需要一个集体的地方,来将这些进行存储,统一管理
构建工具
项目初始化(vue-cli)
- Vue.js 提供一个官方命令行工具vue-cli,可用于快速搭建大型单页应用在此之上,官方基于webpack提供了两种项目模板,分别是vue-webpack-simple模板和vue-webpack模板。该工具提供开箱即用的构建工具配置,带来现代化的前端开发流程。只需几分钟即可创建并启动一个带热重载、保存时静态检查以及可用于生产环境的构建配置的项目:
// 全局安装 vue-cli
npm install --global vue-cli
// 创建一个基于 webpack 模板的新项目
vue init webpack my-project
//这个地方还可以 vue init webpack-simple my-project 建议大家先建立简单模板了解结构,再渐进增强.
// 安装依赖,走你
cd my-project
npm install
npm run dev
ps:npm比较慢,大家可以安装淘宝 NPM 镜像,或用yarn取代
内部去调用main.js,走App.vue的入口,根据路由管理跳转页面,都是经过vue的单页面组件,后面基本不会用到html文件
一个简单的app.vue
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
<style>
html{
padding:0;
margin:0;
width:100%;
height:100%;
}
body{
padding:0;
margin:0;
width:100%;
height:100%;
}
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
min-height:100%;
}
</style>
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue' //引入vue
import App from './App' //引入app.vue
import router from './router/index'
import store from './store/store'
import iView from 'iview'
import 'iview/dist/styles/iview.css'
Vue.config.productionTip = false
Vue.use(iView);
Vue.prototype.HOST = 'http://127.0.0.1:8087/elder_home'
// Vue.prototype.HOST = 'http://192.168.199.239:8087/elder_home'
// Vue.use(axios);
new Vue({
el: '#app',
// router: router,
router,
store,
render: h => h(App)
// template: '<App/>',
// components: { App }//注册app组件
});
补充
- weex,那就是:Native 版本的 vue:http://weex.apache.org/cn/
- VUE有它自己的开发者工具(https://github.com/vuejs/vue-devtools)
- UI组件库:
- vue插件汇总:https://github.com/GyuanHFUT/awesome-vue
- vue重用指令:http://www.cnblogs.com/landeanfen/p/6054654.html#_label2_0
来源
- https://mp.weixin.qq.com/s?__biz=MzIwNjQwMzUwMQ==&mid=2247484393&idx=1&sn=142b8e37dfc94de07be211607e468030&chksm=9723612ba054e83db6622a891287af119bb63708f1b7a09aed9149d846c9428ad5abbb822294&mpshare=1&scene=1&srcid=1026oUz3521V74ua0uwTcIWa&from=groupmessage&isappinstalled=0#wechat_redirect&utm_source=tuicool&utm_medium=referral
- https://www.zybuluo.com/GaoyuanHfut/note/728348