Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架,发布于2014年2月。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库(如:vue-router:跳转,vue -resource:通信,vuex:管理)或既有项目整合
官网
Vue
:一款渐进式JavaScript框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了Angular (模块化)和React (虚拟DOM)的优点Axios
:前端通信框架,因为Vue的边界很明确,就是为了处理DOM,所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互;当然也可以直接选择使用jQuery提供的Ajax通信功能MVVM (Model-View-ViewModel) 是一种软件架构设计模式, 由微软WPF (用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight (类似于Java Applet,简单点说就是在浏览器上运行的WPF)的架构师Ken Cooper和Ted Peters开发,是一种简化用户界面的事件驱动编程方式。由John Gossman (同样也是WPF和Silverlight的架构师)于2005年在他的博客上发表
MVVM源自于经典的MVC (Model-View-Controller) 模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用
MVVM已经较为成熟,当下流行的MVVM框架有vue.js
,Angular.js
View是视图层,也就是看到的用户界面。前端主要由
HTML
和CSS
来构建,为了更方便地展现ViewModel
或者Model
层的数据,已经产生了各种各样的前后端模板语言,比如FreeMarker、Thymeleaf等等,各大MVVM框架如Vue.js, AngularJS, EJS 等也都有自己用来构建用户界面的内置模板语言
Model是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控主要围绕数据库系统展开。这里的难点主要在于需要和前端约定统一的
接口规则
ViewModel是由前端开发人员组织生成和维护的视图数据层。在这-层,前端开发者对从后端获取的Model数据进行转换处理,做二次封装,以生成符合View层使用预期的视图数据模型。MVVM框架已经把最繁琐的一块做好了,我们开发者只需要处理和维护ViewModel,更新数据视图就会自动得到相应更新,真正实现
事件驱动编程
View层展现的不是
Model
层的数据,而是ViewModel
的数据,由ViewModel
负责与Model
层交互,这就完全解耦了View层和Model层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环
在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个Observer观察者
Vue.js就是一个MVVM的实现者。他的核心就是实现了DOM监听与数据双向绑定
Vue.js是一个MVVM枢架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也是Vue.js较为特殊的功能
需要注意的是,我们所说的数据双向绑定,一定是对于 UI控件来说的,非UI 控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理I具的前提。如果我们使用vuex
,那么数据流也是单项的,这时就会和双向数据绑定有冲突
在Vue.js中,如果使用vuex
,实际上数据还是单向的,之所以说是数据双向绑定,这是对于UI控件来说,对于我们处理表单,Vue.js的双向数据绑定使用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。
你可以用 v-model
指令在表单 、
及
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但
v-model
本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
需要注意的是:v-model
会忽略所有表单元素的 value
、checked
、selected
attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data
选项中声明初始值
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>数据双向绑定title>
<script src="../../js/vue.min.js">script>
head>
<body>
<div id="app">
<p>
<label>用户名:label>
<input type="text" v-model="value"/>
<span style="color: coral">值为:{
{value}}span>
p>
div>
<script>
let vm = new Vue({
el: "#app",
data: {
value: "hello vue",
},
});
script>
body>
html>
<div id="app">
<p>
<label>个人简介:label>
<textarea cols="20" rows="10" v-model="value">textarea>
<span style="color: coral">值为:{
{value}}span>
p>
div>
<script>
let vm = new Vue({
el: "#app",
data: {
value: "hello vue",
},
});
script>
<div id="app">
<p>
<label>性别:label>
<input type="radio" name="gender" value="男" v-model="checked"/> 男
<input type="radio" name="gender" value="女" v-model="checked"/> 女
<span style="color: coral">选中了:{
{checked}}span>
p>
div>
<script>
let vm = new Vue({
el: "#app",
data: {
checked: "男",
},
});
script>
<div id="app">
<p>
<label>爱好:label>
<input type="checkbox" value="swim" v-model="checkValue"/> 游泳
<input type="checkbox" value="football" v-model="checkValue"/> 篮球
<input type="checkbox" value="playGame" v-model="checkValue"/> 游戏
<span style="color: coral">选中了:{
{checkValue}}span>
p>
div>
<script>
let vm = new Vue({
el: "#app",
data: {
checkValue: [],
},
});
script>
<div id="app">
城市:
<select name="city" v-model="selected">
<option value="" disabled>---请选择---option>
<option name="henan">河南option>
<option name="luoyang">洛阳option>
<option name="yichuan">伊川option>
select>
<p>选中了:{
{selected}}p>
div>
<script>
let vm = new Vue({
el: "#app",
// Model:数据
data: {
selected: '',
},
});
script>
注:如果 v-model
表达式的初始值未能匹配任何选项, 元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
组件是可复用的Vue
实例,它是一组可以重复使用的模板,通常一个应用会以一棵嵌套的组件树的形式来组织:
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
使用Vue.component()方法注册组件,格式如下:
<div id="app">
<my-component v-for="subject in items" v-bind:source="subject">my-component>
div>
<script type="text/javascript">
//注册组件 Vue.component
Vue.component("myComponent", {
props: ['source'], //可以接收的参数
template: '{
{source}} ', //模板
});
//实例化Vue
let vm = new Vue({
el: "#app",
data: {
items: ["Java", "linux", "HTML", "CSS", "JavaScript"],
},
});
script>
Axios是一个开源的可以用在浏览器端和NodeJS
的异步通信框架,她的主要作用就是实现AJAX异步通信,其功能特点如下:
XMLHttpRequests
中文文档
由于Vue.js
是一个视图层框架,并且作者(尤雨溪)严格准守SoC (关注度分离原则)
,所以Vue.js
并不包含Ajax的通信功能,为了解决通信问题,作者单独开发了一个名为vue-resource
的插件,不过在进入2.0版本以后停止了对该插件的维护并推荐了Axios
框架,少用jQuery,因为它操作Dom太频繁!
由于我们开发的接口大部分都是采用JSON格式,可以先在项目里模拟一段JSON数据,数据内容如下:创建名为data.json的文件并填入上面的内容,放在项目的根目录下
{
"name": "小张",
"age": 18,
"isGrow": true,
"url": "https://www.tmall.com/",
"address": {
"country": "中国",
"city": "洛阳",
"street": "龙门大道"
}
}
测试代码
<div id="app" v-cloak>
<div>{
{info.name}}div>
<div>{
{info.address.country}}div>
<div>{
{info.address.city}}div>
<div>{
{info.address.street}}div>
<a v-bind:href="info.url">click Mea>
div>
<script type="text/javascript">
let vm = new Vue({
el: "#app",
data: {
},
//data属性 vm对象的
//下方data是一个方法,用来接收数据
data() {
return {
//请求的返回参数格式必须和json字符串一样
info: {
name: null,
url: null,
address: {
country: null,
city: null,
street: null,
}
}
}
},
mounted() {
//钩子函数 链式编程 ES6新特性
axios.get('../../data.json').then(response => (this.info = response.data));
}
});
script>
Ajax
响应回来的数据格式匹配!计算属性的重点突出在属性
两个字上(属性是名词),首先它是个属性
其次这个属性有计算
的能力(计算是动词),这里的计算就是个函数;简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性), 仅此而已,可以想象为缓存!
<div id="app">
<p>currentTime方法:{
{currentTime1()}}p>
<p>currentTime属性:{
{currentTime2}}p>
div>
<script type="text/javascript">
let vm = new Vue({
el: "#app", //绑定的元素
data: {
//data数据
msg: "hello vue",
},
methods: {
currentTime1: function () {
return Date.now(); //返回当前时间戳
}
},
computed: {
//计算属性:methods和computed中的方法名不能重名!
currentTime2: function () {
this.msg; //当数据发生改动时,会重新计算
return Date.now(); //返回当前时间戳
}
}
});
script>
调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统开销,如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;
在Vue.js
中我们使用
元素作为承载分发内容的出口,作者称其为插槽
,可以应用在组合组件的场景中;
创建一个课程信息的组件
<div id="app">
<course>
course>
div>
<script type="text/javascript">
//创建一个课程信息的模板
Vue.component('course', {
template:
'\
课程信息
\
\
- Java
\
\
'
});
script>
需要让课程信息的标题和值动态绑定,需要留出一个插槽,将上面的代码留出一个插槽,即slot
<script type="text/javascript">
//创建一个课程信息的模板
Vue.component('course', {
template:
'\
\
\
\
\
'
});
script>
定义一个名为course-title的课程标题组件和course-content的课程内容组件
<script>
//课程标题组件
Vue.component('course-title', {
props: ['title'],
template: '{
{title}}
'
})
//课程内容组件
Vue.component('course-content', {
//这里的index,是数组的下标,使用for循环遍历出来
props: ['item', 'index'],
template: '- {
{index+1}}---{
{item}}
'
})
script>
实例化Vue并初始化数据
<script>
let vm = new Vue({
el: "#app",
data: {
title: "课程信息",
list: ['Java', 'C++', 'C#'],
}
});
script>
将这些值,通过插槽插入
<div id="app">
<course>
<course-title slot="course-title" :title="title">course-title>
<course-content slot="course-content" v-for="(item,index) in list" :item="item"
:index="index">course-content>
course>
div>
通过以上代码不难发现,数据项在Vue的实例中,但删除操作要在组件中完成,那么组件如何才能删除Vue实例中的数据呢?此时就涉及到参数传递与事件分发了,Vue 为我们提供了自定义事件的功能很好的帮助我们解决了这个问题:使用this.$emit(自定义事件名',参数)
,操作过程如下:
在vue的实例中,增加了methods对象并定义了一个名为removeCourseItems的方法
<script>
let vm = new Vue({
el: "#app",
data: {
title: "课程信息",
list: ['Java', 'C++', 'C#'],
},
methods: {
//该方法可以被模板中自定义事件触发
removeCourseItems: function (index) {
console.log("删除了" + this.list[index] + "成功!");
//splice()方法向数组中添加/删除项目,然后返回被删除的项目,其中index为要删除的下标
this.list.splice(index, 1);
},
}
});
script>
修改course-content课程内容组件的代码,添加一个删除按钮,并且绑定事件
<script>
//课程内容组件
Vue.component('course-content', {
//这里的index,是数组的下标,使用for循环遍历出来
props: ['item', 'index'],
//只能绑定当前组件的方法
template: '- {
{index+1}}---{
{item}}
',
methods: {
remove: function (index) {
//this.$emit 自定义事件分发
this.$emit("remove", index);
}
}
});
script>
修改course-content课程内容组件的HTML代码,增加一个自定义事件,比如叫remove,可以和组件的方法绑定,然后绑定到vue的方法中!
<course-content slot="course-content" v-for="(item,index) in list" :item="item"
:index="index" v-on:remove="removeCourseItems(index)">course-content>
核心:数据驱动
,组件化
优点:借鉴了AngulaJS 的模块化开发和React的虚拟Dom ,虚拟Dom就是把Dom操作放到内存中去执行!(集大成者)
常用属性:
简写@
简写:
组件化:
this.$emit("事件名",参数);
遵循SoC关注度分离原则,Vue是纯粹的视图框架,并不包含;比如Ajax之类的通信功能,为了解决通信问题,我们需要使用Axios
框架做异步通信;
Vue的开发都是要基于ModeJS,实际开发采用vue-cli脚手架
开发,vue-router路由;vuex做状态管理; Vue UI界面我们一般使用ElementUl(饿了么出品),或者**IC E(阿里巴巴出品)**来快速搭建前端项目
官网:
elementUl
ice
vue-cli官方提供的一个脚手架,用于快速生成一个vue的项目模板;
预先定义好的目录结构及基础代码,就像咱们在创建Maven项目时可以选择创建一个骨架项目,这个骨架项目就是脚手架,让我们的开发更加的快速;
主要功能:
需要环境:
Node.js
确认nodejs安装成功:
node -v
测试是否安装成功,显示版本号npm-v
测试是否安装成功,显示版本号安装nodejs淘宝镜像加速器(cnpm)
-g 全局安装
npm install cnpm -g
安装位置:C:\Users\86186\AppData\Roaming\npm
安装vue-cli
cnpm install vue-cli -g
测试是否安装成功,查看可以基于那些模板创建vue应用程序,通常选择webpack
vue list
创建一个Vue项目,随便建立一个空的文件夹在电脑上,这里在E盘下
E:\Program Files (x86)\IntelliJ IDEA Project\vue\myvue
创建一个基于webpack模板的vue应用程序
这里的 myvue 是项目名称,可以根据自己需求改变
vue init webpack myvue
一路选择no即可;在指定文件夹生成项目目录
初始化并运行
cd myvue 进入到myvue目录下
npm install 下载依赖
npm run dev 运行
执行完成后,目录多了很多依赖
WebApp
模式。它们完成浏览器的基本需求;WebApp通常是一个SPA (单页面应用)
,每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载大量的JS代码,这给前端的开发流程和资源组织带来了巨大挑战WebPack是一款模块加载器兼打包工具,它能把各种资源,如JS、JSX、ES6、SASS、LESS、图片等都作为模块来处理和使用。
安装:
npm install webpack -g
npm install webpack webpack-cli -g
测试是否安装成功:
webpack -v
webpack-cli -v
使用webpack
创建项目(新建一个空文件夹,用idea打开)
创建名为modules的目录,用于放置JS模块等资源文件
在modules下创建模块文件,如index.js,用于编写JS模块相关代码
//暴露一个方法 sayHi
exports.sayHi = function () {
document.write('<h2>hello ES6h2>');
};
在modules下创建一个名称为main.js的入口文件,用于打包时设置entry属性
//require 导入一个模板,就可以调用该模板中的方法了
var index = require("./index");
index.sayHi();
在项目目录下创建webpack.config.js
配置文件,使用webpack命令打包
module.exports = {
entry: './modules/main.js', //指定webpack用哪个文件作为项目的入口
output: {
filename: './js/bundle.js', //WebPack把处理完成的文件放置到指定路径
},
};
直接使用webpack
命令打包,注:需要idea使用管理员身份运行
Vue Router是Vue.js官方的路由管理器。它和Vue.js的核心深度集成,让构建单页面应用变得易如反掌
安装:
vue-router
是一个插件包,还是需要用npm/cnpm来进行安装,打开命令行工具。进入你的项目目录,输入以下命令
npm install vue-router --save-dev
如果在一个模块化工程使用它,必须要通过Vue.use()
明确的安装路由功能
import Vue from "vue";
import VueRouter from "vue-router";
//安装路由
Vue.use(VueRouter);
测试
先删除项目中没有用的东西
```components`目录下存放自己编写的组件
定义一个Content.vue
的组件
<template>
<h1>内容页h1>
template>
<script>
export default {
name: "Content"
}
script>
<style scoped>
style>
安装路由,在src目录下,新建一个文件夹:router
,专门存放路由(新建一个index.js文件)
import Vue from "vue";
//导入路由插件
import VueRouter from "vue-router";
//导入定义的组件
import Content from "../components/Content";
import Index from "../components/Index"
//安装路由
Vue.use(VueRouter);
//配置导出路由
export default new VueRouter({
routes: [
{
//路由路径
path: "/content",
//路由名称
name: "content",
//跳转的组件
component: Content,
},
{
//路由路径
path: "/index",
//路由名称
name: "index",
//跳转的组件
component: Index,
},
],
});
在mian.js
中配置路由
import Vue from 'vue'
import App from './App'
//导入上面创建的路由配置目录
import router from "./router"
//关闭生产模式下给出的提示
Vue.config.productionTip = false
new Vue({
el: '#app',
//配置路由
router,
components: {
App},
template: ' '
})
在App.vue
中使用路由
<template>
<div id="app">
<h1>Vue-Routerh1>
<router-link to="/index">首页router-link>
<router-link to="/content">内容页router-link>
<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>
注:命令行要使用管理员模式运行
创建一个名称为hello_vue的工程:vue init webpack hello_vue
安装依赖,需要安装vue-router
、element-UI
、sass-loader
、node-sass
四个插件
# 进入到工程目录
cd hello_vue
# 安装vue-router
npm install vue-router --save-dev
# 安装element-ui
npm i element-ui -S
# 安装依赖
cnpm install
# 安装SASS加载器
cnpm install sass-loader node-sass --save-dev
# 启动测试
npm run dev
创建登录页面
在源码目录中创建如下结构:
创建首页视图,在views目录下创建一个名为Main.vue的组件
<template>
<h1>首页h1>
template>
<script>
export default {
name: "Main"
}
script>
<style scoped>
style>
创建登录视图,在views目录下创建一个名为Login.vue的组件
<template>
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="密码" prop="pass">
<el-input type="password" v-model="ruleForm.pass" autocomplete="off">el-input>
el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass" autocomplete="off">el-input>
el-form-item>
<el-form-item label="年龄" prop="age">
<el-input v-model.number="ruleForm.age">el-input>
el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">提交el-button>
<el-button @click="resetForm('ruleForm')">重置el-button>
el-form-item>
el-form>
template>
<script>
export default {
name: "Login",
}
script>
<style scoped>
style>
在router文件夹下创建index.js
,用于注册路由
import Vue from "vue";
import VueRouter from "vue-router"
//导入自己编写的组件
import Index from "../views/Main"
import Login from "../views/Login"
//使用路由
Vue.use(VueRouter);
export default new VueRouter({
routes: [
{
path: "/index",
component: Index
},
{
path: "/login",
component: Login
},
],
});
在mian.js
中配置路由
import Vue from 'vue'
import App from './App'
//导入VueRouter
import router from "./router"
//导入ElementUI相关资源
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(router);
Vue.use(ElementUI);
Vue.config.productionTip = false
new Vue({
el: '#app',
router, //使用路由
render: h => h(App), //使用ElementUI
})
rm’)">重置
在router文件夹下创建``index.js``,用于注册路由
```javascript
import Vue from "vue";
import VueRouter from "vue-router"
//导入自己编写的组件
import Index from "../views/Main"
import Login from "../views/Login"
//使用路由
Vue.use(VueRouter);
export default new VueRouter({
routes: [
{
path: "/index",
component: Index
},
{
path: "/login",
component: Login
},
],
});
在mian.js
中配置路由
import Vue from 'vue'
import App from './App'
//导入VueRouter
import router from "./router"
//导入ElementUI相关资源
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(router);
Vue.use(ElementUI);
Vue.config.productionTip = false
new Vue({
el: '#app',
router, //使用路由
render: h => h(App), //使用ElementUI
})