Vue2
前端概论
前端的四个方面
-
逻辑
- 判断【是否展示】
- 循环
-
事件
- 浏览器事件:window,document
- Dom事件:增,删,遍历,修改节点元素内容
框架JQuery,Vue,react
-
视图
- HTML
- css
框架:BootStrap,Layui
-
通信
- Ajax
- xhr
- axios
CSS预处理器
CSS 预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为 CSS 增加了一些编程的特性,将 CSS 作为目标生成文件,然后开发者就只要使用这种语言进行 CSS 的编码工作。转化成通俗易懂的话来说就是“用一种专门的编程语言,进行 Web 页面样式设计,再通过编译器转化为正常的 CSS 文件,以供项目使用”
常用的 CSS 预处理器有哪些
- SASS:基于 Ruby,通过服务端处理,功能强大。解析效率高。需要学习 Ruby 语言,上手难度高于 LESS。
- LESS:基于 NodeJs,通过客户端处理,使用简单。功能比 SASS 简单,解析效率也低于SASS,但在实际开发中足够了,所以我们后台人员如果需要的话,建议使用 LESS,
JavaScript框架
- jQuery: 大家熟知的 JavaScript 框架,优点是简化了 DOM 操作,缺点是 DOM 操作太频繁影响前端性能;在前端眼里使用它仅仅是为了兼容IE6、7、8;
- Angular: Google 收购的前端框架,由一群 Java 程序员开发,其特点是将后台的 MVC 模式搬到了前端并增加了模块化开发的理念,与微软合作,采用 TypeScript 语法开发;对后台程序员友好,对前端程序员不太友好:最大的缺点是版本迭代不合理(如:1代->2代,除了名字,基本就是两个东西,歇菜了
- React: Facebook 出品,一款高性能的JS 前端框架;特点是提出了新概念 【虚拟 DOM】 用于减少真实 DOM 操作,在内存中模拟 DOM 操作,有效的提升了前端渲染效率:缺点是使用复杂,因为需要额外学习一门【JSX】 语言;
- Vue: 一款渐进式 JavaScript 框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了 Angular(模块化)和 React(虚拟 DOM)的优点;
- Axios:前端通信框架;因为 vue的边界很明确,就是为了处理 DOM,所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互;当然也可以直接选择使用 jQuery 提供的AJAX 通信功能:
UI框架
- Ant-Design:阿里巴巴出品,基于 React 的 Ul框架。
- ElementUl、iview、ice:饿了么出品,基于 Vue 的 Ul 框架
- Bootstrap: Twitter推出的一个用于前端开发的开源工具包。
- AmazeUl:一款 HTML5 跨屏前端框架
JavaScript构建工具
- Babel: JS 编译工具,主要用于浏览器不支持的 ES 新特性,比如用于编译 TypeScript
- WebPack:模块打包器,主作用是打包、压缩、合并及按序加载
Vue
什么是MVVM
MVVM (Model-View-ViewModel)是一种软件架构设计模式,由微软 WPF(用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和 Silverlight(类似于 Java Applet,简单点说就是在浏览器上运行的 WPF)的架构师 Ken Cooper 和 Ted Peters 开发,是一种简化用户界面的事件驱动编程方式。由John Gossman(同样也是 WPF 和 Silverlight 的架构师)于 2005 年在他的博客上发表。
MVVM 源自于经典的 MVC(Model-View-CoNroller)模式。MVVM 的核心是 ViewModel层,负责转换 Model 中的数据对象来让数据变得更容易管理和使用,其作用如下:
- 该层向上与视图层进行双向数据绑定
- 向下与 Model 层通过接口请求进行数据交互
MVVM 已经相当成熟了,主要运用但不仅仅在网络应用程序开发中。当下流行的 MVVM 框架有Vue.js,AngularJs 等
为什么要使用MVVM
MVVM 模式和 MVC 模式一样,主要目的是分离视图(View)和模型(Model),有几大好处
- 低耦合: 视图(View)可以独立于 Model 变化和修改,一个 ViewModel 可以绑定到不同的View 上,当 View 变化的时候 Model 可以不变,当 Model 变化的时候 View 也可以不变。
- 可复用:你可以把一些视图逻辑放在一个 ViewModel 里面,让很多 View 重用这段视图逻辑。
- 独立开发: 开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
- 可测试:界面素来是比较难于测试的,而现在测试可以针对 ViewModel 来写。
MVVM的组成
-
View
View 是视图层,也就是用户界面。前端主要由 HTML和css 来构建,为了更方便地展现ViewModel 或者 Model 层的数据,已经来生了各种各样的前后端模板语言,比如 FreeMarker、Thymeleaf 等等,各大 MVVM 框架如 Vue.jis,AngularJS,EJS 等也都有自己用来构建用户界面的内置模板语言。
-
Model
Model是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,主要围绕数据库系统展开。这里的难点主要在于需要和前端约定统一的 接口规则
-
ViewModel
ViewModel是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。
需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分,而 Model 层的数据模型是只包含状态的- 比如页面的这一块展示什么,那一块展示什么这些都属于视图状态(展示)
- 页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交日)
视图状态和行为都封装在了 ViewModel 里。这样的封装使得 ViewModel 可以完整地去描述View 层”。由于实现了双向绑定,ViewModel 的内容会实时展现在 View 层,这是激动人心的,因为前端开发者再也不必低效又麻烦地通过操纵 DOM 去更新视图。
MVVM 框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护 ViewModel,更新数据视图就会自动得到相应更新,真正实现事件驱动编程。
View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。
Vue
Vue (读音 /vju/,类似于 view) 是一套用于构建用户界面的渐进式框架,发布于 2014 年2月。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库(如:vue-router:跳转,vue-resource:通信,vuex:管理)或既有项目整合。
Vue ——MVVM模式的实现者
- Model:模型层,在这里表示JavaScript 对象
- View:视图层,在这里表示 DOM(HTML操作的元素)
- ViewModel:连接视图和数据的中间件,Vue.js 就是 MVVM 中的 ViewModel 层的实现者
在 MVVM 架构中,是不允许 数据 和 视图 直接通信的,只能通过 ViewModel 来通信,ViewModel 就是定义了一个 Observer 观察者
- ViewModel能够观察到数据的变化,并对视图对应的内容进行更新
- ViewModel 能够监听到视图的化,并能够通知数据发生改变
至此,我们就明白了,Vue.js 就是一个 MVVM 的实现者,他的核心就是实现了 DOM 监听 与据绑定
为什么使用Vue.js
- 轻量级,体积小是一个重要指标。Vue.js 压缩后有只有 20多kb (Angular 压缩后 56kb+React 压缩后 44kb+)
- 移动优先。更适合移动端,比如移动端的Touch 事件
- 易上手,学习曲线平稳,文档齐全
- 吸取了 Angular(模块化)和 React(虚拟 DOM)的长处,并拥有自己独特的功能,如:计算属性
- 开源,社区活跃度高
第一个Vue程序(仿)
用Idea的话用在里面安装Vue插件,这里还没下载Vue用了cdn模式,在线引入
浏览器效果
(Vue.assets/image-20250313221429140.png)
通过程序可以感受到Vue的特点
- 在控制台更改数据,页面不用刷新就能更新数据。因为是通过ajax实现的。
- 另外之所以改完数据就可以实现更新数据,是因为Vue的虚拟DOM功能
- 同时可以注意到这里分类了视图和模型细节分类了,这样可以让后端轻松一点,把数据给到就行,很专业不用动模板
Vue基本语法
v-bind简写:
我们已经成功创建了第一个 Vue 应用!看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被建立了关联,所有东西都是响应式的。我们在控制台操作对象属性,界面可以实时更新!
出来用{{}},我们还可以使用 v-bind 来绑定元素特性!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<span v-bind:title="message">
鼠标悬停显示message信息
</span>
</div>
<!--导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
<!-- 可以创建多个Vue对象,每个对象可以绑定对象-->
var vm = new Vue({
// 元素绑定,当然可以用多个
el:"#app",
// data对象中数据时键值对
data:{
message: "helloVue"
}
});
</script>
</body>
</html>
v-bind 等被称为指令。指令带有前缀 v-,以表示它们是 Vue 提供的特殊特性。可能你已经猜到了,它们会在渲染的 DOM 上应用特殊的响应式行为。在这里,该指令的意思是:"将这个元素节点的 title 特性和 Vue 实例的 message 属性保持一致”
如果你再次打开浏览器的 JavaScript 控制台,输入 app.message ='新消息',就会再一次看到这个绑定了 title 特性的 HTML 已经进行了更新。
v-if,v-else,v-else-if
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h1 v-if="ok">Yes</h1>
<h1 v-else>No</h1>
<h1 v-if="type==='A'">A</h1>
<h1 v-else-if="type==='B'">B</h1>
<h1 v-else>C</h1>
</div>
<!--导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
<!-- 可以创建多个Vue对象,每个对象可以绑定对象-->
var vm = new Vue({
// 元素绑定,当然可以用多个
el:"#app",
// data对象中数据时键值对
data:{
ok: true,
type: 'A'
}
});
</script>
</body>
</html>
v-for
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<li v-for="itme in itmes">
{{itme.message}}
</li>
</div>
<!--导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
<!-- 可以创建多个Vue对象,每个对象可以绑定对象-->
var vm = new Vue({
// 元素绑定,当然可以用多个
el: "#app",
// data对象中数据时键值对
data: {
// []是数组,{}是对象
itmes: [
{message: 'hello'},
{message: 'world'},
{message: 'Vue'}
]
}
});
</script>
</body>
</html>
v-on简写@
事件有Vue的事件、和前端页面本身的一些事件!我们这里的click 是vue的事件,可以绑定到Vue中的 methods 中的方法事件!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button v-on:click="speak">hello</button>
</div>
<!--导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
<!-- 可以创建多个Vue对象,每个对象可以绑定对象-->
var vm = new Vue({
// 元素绑定,当然可以用多个
el:"#app",
// data对象中数据时键值对
data: {
message: 'hello'
},
// 方法必须在methods中
methods: {
speak: function () {
alert(this.message)
}
}
});
</script>
</body>
</html>
Vue还有一些基本的使用方式,大家有需要的可以再跟着官方文档看看,因为这些基本的指令几乎我们都见过了,一通百通!掌握学习的方式!
Vue表单双绑
什么是双向数据绑定
Vue.js 是一个 MVVM 框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是 Vue.js 的精髓之处了
值得注意的是,我们所说的数据双向绑定,一定是对于 UI控件来说的,非 UI 控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用 vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突。
为什么要实现数据的双向绑定
在 Vue.js中,如果使用 vuex,实际上数据还是单向的,之所以说是数据双向绑定,这是用的UI 控件来说,对于我们处理表单,Vue.js 的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪:局部性数据流使用双向,简单易操作。
在表单中使用双向数据绑定
可以用 v-model 指令在表单<input>
、<textarea>
及<select>
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
注意:v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值而总是将Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
input输入的文件:<input type="text" v-model="message1"/> {{message1}}
<hr/>
textarea输入的文件:<textarea v-model="message2"></textarea> {{message2}}
<hr/>
输入的文件:<input type="radio" name="sex" value="男" v-model="message3"/>男
<input type="radio" name="sex" value="女" v-model="message3"/>女
选择结果:{{message3}}
<hr/>
<select v-model="message4">
<option value="" disabled>----请选择----</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>{{message4}}</span>
</div>
<!--导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
<!-- 可以创建多个Vue对象,每个对象可以绑定对象-->
var vm = new Vue({
// 元素绑定,当然可以用多个
el:"#app",
// data对象中数据时键值对
data: {
message1: '',
message2: '',
message3: '',
message4: ''
}
});
</script>
</body>
</html>
表单校验
- 组件前缀
<el-form>
- 模型绑定
:model="form"
- 校验规则
:rules="rules"
- 表单引用
ref="form"
+this.$refs.form
- 触发方式
this.$refs.form.validate()
- 表单重置
this.$refs.form.resetFields()
- 校验回调
(valid) => { ... }
注意:上面绑定的变量名不是固定的,只要和已有想用代码的对应即可
示例
<template>
<el-form :model="form" :rules="rules" ref="ruleForm" label-width="80px">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
form: {
username: "",
email: "",
},
// ✅ Vue2 写法的 rules
rules: {
username: [
{ required: true, message: "请输入用户名", trigger: "blur" },
{ min: 2, max: 10, message: "长度在2~10个字符之间", trigger: "blur" },
],
email: [
{ required: true, message: "请输入邮箱", trigger: "blur" },
{ type: "email", message: "邮箱格式不正确", trigger: ["blur", "change"] },
],
},
};
},
methods: {
submitForm() {
// Vue2 手动验证写法
this.$refs.ruleForm.validate((valid) => {
if (valid) {
this.$message.success("验证通过!");
} else {
this.$message.error("请填写完整表单!");
return false;
}
});
},
resetForm() {
this.$refs.ruleForm.resetFields();
},
},
};
</script>
Vue组件
组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际应用中,组件常常被组织成一个层层嵌套的树状结构:
这和我们嵌套 HTML 元素的方式类似,Vue 实现了自己的组件模型,使我们可以在每个组件内封装自定义内容与逻辑。Vue 同样也能很好地配合原生 Web Component。
第一个Vue组件
注意:在实际开发中,我们并不会用以下方式开发组件,而是采用 vue-cli 创建 .vue 模板文件的方式开发,以下方法只是为了让大家理解什么是组件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--绑定的属性名也可以自定义,不会报错-->
<ario v-for="item in items" v-bind:ariovalue="item"></ario>
</div>
<!--导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
//定义一个Vue组件component,名字起airo
Vue.component("ario",{
//用props传递组件中的值
props: ['ariovalue'],
template: '<li>{{ariovalue}}</li>'
});
var vm = new Vue({
el:"#app",
data: {
items: ["java", "Linux", "前端"]
}
});
</script>
</body>
</html>
Axios异步通信
什么是Axios
Axios是一个开源的可以用在浏览器端和NodeJS的异步通信框架,她的主要作用就是实现AJAX异步通信,其功能特点如下:
- 从浏览器中创建XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API [JS中链式编程]
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF(跨站请求伪造)
为什么要使用Axios
由于 Vue.js 是一个视图层框架并且作者(尤雨溪)严格准守 SoC(关注度分离原则),所以vue.js 并不包含 AJAX 的通信功能,为了解决通信问题,作者单独开发了一个名为 vue-resource的插件,不过在进入 2.0 版本以后停止了对该插件的维护并推荐了 Axios 框架。少用jQuery,因为它操作Dom太频繁!
第一个Axios应用程序
日常开发的接口大部分都是采用JSON格式, 可以先在项目里模拟一段JSON数据, 数据内容如下:
-
创建一个名为data.json的文件并填入上面的内容, 放在项目的根目录下
{ "name": "airo", "url": "https://www.cnblogs.com/arioya/", "page": 1, "isNonProfit": true, "address": { "street": "万柏林", "city": "山西太原", "country": "中国" }, "links": [ { "name": "语雀", "url": "https://www.yuque.com/nizhegechouloudetuboshu/library" }, { "name": "ario", "url": "https://www.cnblogs.com/arioya/" }, { "name": "百度", "url": "https://www.baidu.com/" } ] }
-
前端代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- v-clock:解决闪烁问题,让其渲染之前设置为不展示,[]选择器--> <style> [v-cloak]{ display: none; } </style> </head> <body> <div id="app"> <div v-cloak>{{info.name}}</div> <div>{{info.address.city}}</div> <a v-bind:href="info.url">跳转</a> </div> <!--导入Vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> var vm = new Vue({ el:"#app", //这里是函数,下面有return data() { return { //请求的返回参数合适,必须和json字符串已有 info: { name: null, address: { street: null, city: null, country: null }, url: null } } }, mounted(){//钩子函数,链式编程 axios.get('../data.json').then(response=>(this.info=response.data)) } }); </script> </body> </html>
-
效果图
Vue的生命周期
Vue实例有一个完整的生命周期,也就是从开始创建初始化数据、编译模板、挂载DOM、渲染一更新一渲染、卸载等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,就是生命周期
在Vue的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册JS方法,可以让我们用自己注册的JS方法控制整个大局,在这些事件响应方法中的this直接指向的是Vue的实例。
周期 | 说明 |
---|---|
beforeCreate | 在实例初始化之后,数据观测和事件配置之前被调用 |
created | 在实例创建完成后被立即调用,完成数据观测,属性和方法的运算,初始化事件,$el属性未见 |
beforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用,只在虚拟DOM生成HTML |
mounted | 在el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互 |
beforeUpdate | 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程 |
updated | 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用 |
activated | keep-alive 组件激活时调用 |
deactivated | keep-alive 组件停用时调用 |
beforeDestroy | 在实例销毁之前调用。实例仍然完全可用 |
destroyed | 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用 |
计算属性
计算属性的重点突出在属性两个字上(属性是名词),首先它是个 属性 其次这个属性有 计算的能力(计算是动词),这里的 计算就是个函数;简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层,模板-->
<div id="app">
<p>currentTime1:{{currentTime1()}}</p>
<p>currentTime2:{{currentTime2}}</p>
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
message:"message"
},
methods:{
currentTime1:function(){
return Date.now();//返回一个时间戳
}
},
computed:{
currentTime2:function(){//计算属性:methods,computed方法名不能重名,重名之后,只会调用methods的方法
this.message;
return Date.now();//返回一个时间戳
}
}
});
</script>
</body>
</html>
注意:methods和computed里的东西不能重名。
说明:
- methods:定义方法, 调用方法使用currentTime1(), 需要带括号
- computed:定义计算属性, 调用属性使用currentTime2, 不需要带括号:this.message是为了能够让currentTime2观察到数据变化而变化
- 如何在方法中的值发生了变化,则缓存就会刷新!可以在控制台使用
vm.message=”qinjiang"
, 改变下数据的值,再次测试观察效果
结论:
调用方法时,每次都需要讲行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;
内容分发
在Vue.js
中我们使用<slot>
元素作为承载分发内容的出口,作者称其为插槽,可以应用在组合组件的场景中;
测试
比如准备制作一个待办事项组件(todo) , 该组件由待办标题(todo-title) 和待办内容(todo-items)组成,但这三个组件又是相互独立的,该如何操作呢?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
<todo>
<todo-title slot="todo-title" :title="title"></todo-title>
<!-- <todo-items slot="todo-items" v-for="(item, index) in todoItems" v-bind:item="item" v-bind:index="index"></todo-items>-->
<!-- 如下为简写 -->
<todo-items slot="todo-items" v-for="(item, index) in todoItems" :item="item" :index="index"></todo-items>
</todo>
</div>
<!-- 1.导入Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
<!-- \可以实现换行-->
Vue.component('todo',{
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
Vue.component('todo-title',{
props:['title'],
template: '<div>{{title}}</div>'
});
// 这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
Vue.component('todo-items',{
props: ['item','index'],
template: '<li>{{index+1}},{{item}}</li>'
});
var vm = new Vue({
el: '#app',
data: {
title: 'Vue学习笔记',
todoItems: ['Java','前端','运维','安卓']
}
});
</script>
</body>
</html>
自定义事件
通以上代码不难发现,数据项在Vue的实例中, 但删除操作要在组件中完成, 那么组件如何才能删除Vue实例中的数据呢?此时就涉及到参数传递与事件分发了, Vue为我们提供了自定义事件的功能很好的帮助我们解决了这个问题; 使用this.$emit(‘自定义事件名’, 参数) , 操作过程如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层 模板-->
<div id="app">
<todo>
<todo-title slot="todo-title" :title="title"></todo-title>
<!--增加了v-on:remove="removeTodoItems"自定义事件,该组件会调用Vue实例中定义的,事件绑定v-on或@-->
<todo-items slot="todo-items" v-for="(item, index) in todoItems" :item="item" :index="index" @remove="removeItems"></todo-items>
<div>Vue</div>
<div>Vue</div>
<div>Vue</div>
<div slot="num">Vue</div>
</todo>
</div>
<!-- 1.导入Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
Vue.component('todo',{
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
\<h1><slot></slot></h1>\
\<h2><slot name="num"></slot></h2>\
</div>'
});
Vue.component('todo-title',{
props:['title'],
template: '<div>{{title}}</div>'
});
// 这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
Vue.component('todo-items',{
props: ['item','index'],
template: '<li>{{index}}——{{item}}<button @click="remove">删除</button></li>',
methods: {
remove(index) {
this.$emit('remove',index)
}
}
});
var vm = new Vue({
el:"#app",
// Model:数据
data:{
title: 'Vue学习笔记',
todoItems: ['Java','前端','运维','安卓']
},
methods: {
removeItems(index) {
console.log("删除了" + this.todoItems[index] + "OK")
this.todoItems.splice(index,1) // 一次删除一个元素
}
}
});
</script>
</body>
</html>
Vue入门小结
- 核心:数据驱动,组件化。
- 优点:借鉴了AngularJS的模块化开发和React的虚拟Dom,虚拟Dom就是把Demo操作放到内存中执行。
常用的属性:
- v-if
- v-else-if
- v-else
- v-for
- v-on绑定事件,简写@
- v-model数据双向绑定
- v-bind绑定参数,简写:
组件化:
- 组合组件slot插槽
- 组件内部绑定事件需要使用到
this.$emit("事件名",参数);
- 计算属性的特色,缓存计算数据
遵循SoC关注度分离原则,Vue是纯粹的视图框架,并不包含,比如Ajax之类的通信功能,为了解决通信问题,我们需要使用Axios框架做异步通信;
说明
Vue的开发都是要基于NodeJS,实际开发采用Vue-cli脚手架开发,vue-router路由,vuex做状态管理;Vue UI,界面我们一般使用ElementUI(饿了么出品),或者ICE(阿里巴巴出品)来快速搭建前端项目~~
第一个Vue-cli项目
什么是vue-cli
- vue-cli官方提供的一个脚手架,用于快速生成一个vue的项目模板。
- 预先定义好的目录结构及基础代码,就好比咱们在创建Maven项目时可以选择创建一个骨架项目,这个估计项目就是脚手架,我们的开发更加的快速。
主要的功能
- 统一的目录结构
- 本地调试
- 热部署
- 单元测试
- 集成打包上线
需要的环境
安装nodejs:
- Node.js:http://nodejs.cn/download/
- 安装就是无脑的下一步就好,安装在自己的环境目录下。nvm和nodejs安装
- Git:https://git-scm.com/doenloads
- 镜像:https://npm.taobao.org/mirrors/git-for-windows/
- cmd下输入
node -v
,查看是否能够正确打印出版本号即可! - cmd下输入
npm -v
查看是否能够正确打印出版本号即可!- 这个npm,就是一个软件包管理工具,就和linux下的apt软件安装差不多!
安装Node.js淘宝镜像加速器(cnpm)
# -g 就是全局安装
npm install cnpm -g
# 或使用如下语句解决npm速度慢的问题
npm install --registry=https://registry.npm.taobao.org
- 安装的过程可能有点慢~,耐心等待!虽然安装了cnpm,但是尽量少用!因为可能下载的不能用
- 用npm root -g命令查看下载地址
安装vue-cli
cnpm install vue-cli -g
# 测试是否安装成功
# 查看可以基于哪些模板创建vue应用程序,通常我们选择webpack
vue list
这里vue list连接超时了,整了半天,也没弄好。
然后问了半天豆包,换了一下网络,可以了。感觉好无语哈哈哈。还是豆包靠谱
第一个vue-cli程序
创建项目
- 创建一个Vue项目,我们随便建立一个空的文件夹在电脑上,我这里在D盘下新建一个目录
"D:\code\precode"
。 - 创建一个基于webpack模板的vue应用程序。
#1、首先需要进入到对应的目录 cd D:\code\precode
#2、这里的myvue是项目名称,可以根据自己的需求起名
vue init webpack myvue
- 一路都选择no即可。
血的教训:不要再文件夹中直接打开命令行,要一步的切换到对应目录。
然后输入vue init webpack myvue
说明:
- Project name:项目名称,默认回车即可
- Project description:项目描述,默认回车即可
- Author:项目作者,默认回车即可
- Vue build:选第一个就行
- Install vue-router:是否安装vue-router,选择n不安装(后期需要再手动添加)
- Use ESLint to lint your code:是否使用ESLint做代码检查,选择n不安装(后期需要再手动添加)
- Set up unit tests:单元测试相关,选择n不安装(后期需要再手动添加)
- Setupe2etests with Nightwatch:单元测试相关,选择n不安装(后期需要再手动添加)
- Should we run npm install for you after the,project has been created:创建完成后直接初始化,选择n,我们手动执行;运行结果!
初始化
cd myvue
npm install
运行
2.运行
npm run dev
-
退出服务器,在CMD中按Ctrl+C,输入Y。
-
执行完成后,目录多了很多依赖:
WebPack的使用
什么是Webpack
- 本质上, webpack是一个现代JavaScript应用程序的
静态模块打包器
(module bundler) 【相当于maven】。 - 工作原理:当webpack处理应用程序时, 它会递归地构建一个依赖关系图(dependency graph) , 其中包含应用程序需要的每个模块, 然后将所有这些模块打包成一个或多个bundle。
- Webpack是当下最热门的前端资源模块化管理和打包工具, 它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分离,等到实际需要时再异步加载。通过loader转换, 任何形式的资源都可以当做模块, 比如Commons JS、AMD、ES 6、CSS、JSON、Coffee Script、LESS等;
- 伴随着移动互联网的大潮, 当今越来越多的网站已经从网页模式进化到了WebApp模式。它们运行在现代浏览器里, 使用HTML 5、CSS 3、ES 6等新的技术来开发丰富的功能, 网页已经不仅仅是完成浏览器的基本需求; WebApp通常是一个SPA(单页面应用) , 每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的JS代码,这给前端的开发流程和资源组织带来了巨大挑战。
- 前端开发和其他开发工作的主要区别,首先是前端基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器的,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。
模块化的演进
Script标签
<script src = "module1.js"></script>
<script src = "module2.js"></script>
<script src = "module3.js"></script>
这是最原始的JavaScript文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在window对象中,不同模块的调用都是一个作用域。
这种原始的加载方式暴露了一些显而易见的弊端:
- 全局作用域下容易造成变量冲突。
- 文件只能按照
<script>
的书写顺序进行加载。 - 开发人员必须主观解决模块和代码库的依赖关系。
- 在大型项目中各种资源难以管理,长期积累的问题导致代码库混乱不堪。
CommonsJS
服务器端的NodeJS遵循CommonsJS规范,该规范核心思想是允许模块通过require方法来同步加载所需依赖的其它模块,然后通过exports或module.exports来导出需要暴露的接口。
require("module");
require("../module.js");
export.doStuff = function(){};
module.exports = someValue;
优点:
- 服务器端模块便于重用。
- NPM中已经有超过45万个可以使用的模块包。
- 简单易用。
缺点:
- 同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载【会显得比较卡】,浏览器资源是异步加载的。
- 不能非阻塞的并行加载多个模块。
实现:
- 服务端的NodeJS。
- Browserify,浏览器端的CommonsJS实现,可以使用NPM的模块,但是编译打包后的文件体积较大。
- modules-webmake,类似Browserify,但不如Browserify灵活。
- wreq,Browserify的前身。
AMD
Asynchronous Module Definition规范其实主要一个主要接口。define(id?,dependencies?,factory);它要在声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行。
define("module",["dep1","dep2"],functian(d1,d2){
return someExportedValue;
});
require(["module","../file.js"],function(module,file){});
优点
- 适合在浏览器环境中异步加载模块。
- 可以并行加载多个模块。
缺点
- 提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不畅。
- 不符合通用的模块化思维方式,是一种妥协的实现。
实现
- RequireJS
- curl
CMD
Commons Module Definition规范和AMD很相似,尽保持简单,并与CommonsJS和NodeJS的Modules规范保持了很大的兼容性。
define(function(require,exports,module){
var $=require("jquery");
var Spinning = require("./spinning");
exports.doSomething = ...;
module.exports=...;
});
优点:
- 依赖就近,延迟执行。
- 可以很容易在NodeJS中运行缺点。
- 依赖SPM打包,模块的加载逻辑偏重。
实现
- Sea.js
- coolie
ES6模块
EcmaScript 6标准增加了JavaScript语言层面的模块体系定义。ES 6模块的设计思想, 是尽量静态化, 使编译时就能确定模块的依赖关系, 以及输入和输出的变量。Commons JS和AMD模块,都只能在运行时确定这些东西。
import "jquery"
export function doStuff(){}
module "localModule"{}
优点
- 容易进行静态分析。
- 面向未来的EcmaScript标准。
缺点
- 原生浏览器端还没有实现该标准。
- 全新的命令,新版的Node JS才支持。
实现
- Babel
大家期望的模块
系统可以兼容多种模块风格, 尽量可以利用已有的代码, 不仅仅只是JavaScript模块化, 还有CSS、图片、字体等资源也需要模块化。
安装Webpack
WebPack是一款模块加载器兼打包工具, 它能把各种资源, 如JS、JSX、ES 6、SASS、LESS、图片等都作为模块来处理和使用。
- 安装(管理员身份进入CMD安装):
npm i webpack webpack-cli -g
# 或
yarn global add webpack webpack-cl # 一次性全局安装两个模块
- 测试安装成功【本人这里出错了,但是可以再局部安装,全局安装失败】
webpack -v
webpack-cli -v
# 或
webpack --version
-
局部安装
先在项目文件夹里,用
npm init -y
初始化一个新的项目,然后在这个项目里用npm install webpack webpack-cli --save-dev
局部安装 Webpack 和相关工具。装好后在项目里运行npx webpack -v
就能查看版本啦
配置
创建
webpack.config.js
配置文件
- entry:入口文件, 指定Web Pack用哪个文件作为项目的入口
- output:输出, 指定WebPack把处理完成的文件放置到指定路径
- module:模块, 用于处理各种类型的文件
- plugins:插件, 如:热更新、代码重用等
- resolve:设置路径指向
- watch:监听, 用于设置文件改动后直接打包
module.exports = {
entry:"",
output:{
path:"",
filename:""
},
module:{
loaders:[
{test:/\.js$/,;\loade:""}
]
},
plugins:{},
resolve:{},
watch:true
}
- 直接运行
webpack
命令打包。
使用webpack
-
创建项目(创建一个空文件夹,用idea打开)。
-
创建一个名为modules的目录,用于放置JS模块等资源文件。
-
在modules下创建模块文件,如hello.js,用于编写JS模块相关代码。
// 暴露一个方法
exports.sayHi = function() {
document.write("<h1>Java全栈笔记学习</h1>")
}
- 在modules下创建一个名为main.js的入口文件,用于打包时设置entry属性。
// require 导入一个模块,就可以调用这个模块中的方法了
var hello = require("./hello");
hello.sayHi();
- 在项目目录下创建webpack.config.js配置文件,使用webpack命令打包。
/**
* webpack的配置
*/
// 引入path模块
const path = require('path')
// 把整个配置暴露出去
module.exports = {
// 入口 [以这个文件为入口 开始打包]
entry:"./modules/main.js",
// 出口
output:{
path: path.resolve(__dirname, 'dist'), // 要输出的路径 必须是一个绝对路径
filename:"./js/bundle.js", // 输出的文件名,最终打包出来的文件 叫什么名字(bundle)
publicPath:"./"
},
// 模式
mode: "development", // 开发模式
}
这里再idea中执行报错,再命令行中执行成功,
- 在项目目录下创建HTML页面,如index.html,导入webpack打包后的JS文件。不用哪些碎片文件了
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ario</title>
</head>
<body>
<script src="dist/js/bundle.js"></script>
</body>
</html>
-
在IDEA控制台中直接执行
webpack
;如果失败的话,就使用管理员权限运行即可! -
运行HTML看效果。
- 说明
# 参数--watch 用于监听变化,可以实现热部署。修改文件可以理解效果可以迅速响应 webpack --watch
核心loader
概念
- webpack默认只能打包
javaScript
, 不能处理其他类型的文件,需要loader,loader可以把其他格式的文件,处理成webpack
能正常打包的东西。
1.loader处理css
- 下载loader[管理员身份]
yarn add css-loader style-loader -D
# 或
npm i css-loader style-loader -D
- 配置loader
// 配置loader
module: {
// 规则
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'], // 处理这个格式的文件 需要使用哪些loader
/*
说明:
css-loader: 解析css,让webpack可以识别打包css代码
style-loader: 把css通过style标签,插入到html的header中,才能生效
注意: use数组中,loader解析是有顺序的,从右到左。
*/
},
]
},
2.loader处理less
-
概念:less是css的预处理语言,增强了css的写法,可以写:
嵌套
变量
, less直接引入不能生效,需要编译成css引入才能生效。 -
编译方式: vscode自带插件:
Easy-LESS
(黄黄那个) -
loader处理less
- 下载对应的loader
yarn add less-loader less -D
- 配置loader
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'], // 处理这个格式的文件 需要使用哪些loader },
3.loader处理img
处理less或css中写的背景图
- 下载对应的loader
yarn add url-loader file-loader -D
- 配置这个loader
{
test: /\.(png|jpg|gif)$/,
loader: 'url-loader', // 使用这个loader 处理这种格式的文件
options: { // 写上自己定义的配置
name: '[hash].[ext]', // 输出图片的名字
limit: 10 * 1024, // 限制大小 大于这个值的图片 单独输出 不打包到bundle.js中, 否则打出来的包比较大。小图就直接打包进去,经过base64转码。
}
},
打包html & 打包html中引入的img图片
- 下载对应的 loader 和 打包html的插件
yarn add html-loader html-webpack-plugin@next -D
- 写上对应的配置
- loader的配置
{
test: /\.(png|jpg|gif)$/,
loader: 'url-loader', // 使用这个loader 处理这种格式的文件
options: { // 写上自己定义的配置
name: '[hash].[ext]', // 输出图片的名字
limit: 10 * 1024, // 限制大小 大于这个值的图片 单独输出 不打包到bundle.js中, 否则打出来的包比较大。小图就直接打包进去,经过base64转码。
esModule: false, // 关闭es6的模块化 全部使用node的模块化
}
},
{
test: /\.html$/,
use: ['html-loader'], // 处理这个格式的文件 需要使用哪些loader
},
- 插件的配置
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入插件
// 插件
plugins: [
// 使用插件 这个插件是把 html 打包到 dist 里面
new HtmlWebpackPlugin({
template: "./src/index.html", // 你要以哪个html为模板 进行打包
})
],
4.打包字体图标
- 下载对应的loader(前面处理img以及下载过了)
yarn add file-loader -D
- 配置
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
use: ['file-loader'], // 处理这个格式的文件 需要使用哪些loader
},
5.es6编译到es5
-
下载对应的loader和模块
yarn add babel-core babel-loader@7.1.5 babel-preset-es2015 -D
-
配置
{ test: /\.js$/, use: ['babel-loader'], // 处理这个格式的文件 需要使用哪些loader exclude: /node_modules/, // 排除 }
-
在项目的根目录 创建 .babelrc 文件
{ "presets": [ "es2015" ] }
插件
插件的使用步骤
-
下载插件
yarn add 插件名 -D
-
引入插件
const 变量名 = require('插件名')
-
new插件,在里面写配置
plugins: [ new 变量名({ key: val // 写配置 }) ]
打包html的插件
-
下载插件
yarn add html-webpack-plugin@next -D
-
引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
-
new插件,在里面写配置
plugins: [ // 打包html的插件 new HtmlWebpackPlugin({ template: "./src/index.html", // 以哪个html为模板 filename: "home.html", // 输出的文件名 // 压缩优化 // minify: { // collapseWhitespace: true, // 移除空格 // removeComments: true, // 移除注释 // }, }), ]
-
注意: index.html本身只是模板,不需要引入东西,打包出来的,会自动引入。
提取css的插件
-
下载插件
yarn add mini-css-extract-plugin -D
-
引入插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
-
new插件,在里面写配置
plugins: [ // 使用提取css的插件 (把css从 bundle里面弄出来) new MiniCssExtractPlugin({ filename: "index.css", }), ]
-
注意: index.html本身只是模板,不需要引入东西,打包出来的,会自动引入。
压缩css
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') // 压缩css
// 压缩css
new OptimizeCssAssetsWebpackPlugin()
启动开发服务器
- 全局安装 & 本地安装 webpack-dev-server
yarn global add webpack-dev-server
yarn add webpack-dev-server -D
- 配置
// 开发服务器
devServer: {
contentBase: path.resolve(__dirname, 'dist'), // 启动服务器目录
compress: true, // 启动gzip
port: 8848, // 端口
open: true, // 自动打开服务
openPage:"home.html"//打开指定页面
},
- 启动
webpack serve
- 修改
package.json
"scripts": {
"serve": "webpack serve",
"build": "webpack --progress"
},
- 运行命令:
启动开发服务器: yarn serve
打包: yarn build
完整配置
package.json
{
"name": "fitness-app",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"serve": "webpack serve",
"build": "webpack --progress"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "7.1.5",
"babel-preset-es2015": "^6.24.1",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^5.0.1",
"file-loader": "^6.2.0",
"html-loader": "^1.3.2",
"html-webpack-plugin": "4.5.0",
"less": "^3.12.2",
"less-loader": "^7.1.0",
"mini-css-extract-plugin": "^1.3.2",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-loader": "^4.1.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^2.0.0",
"url-loader": "^4.1.1",
"webpack": "5.10.1",
"webpack-cli": "^4.2.0",
"webpack-dev-server": "^3.11.0"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.1%",
"not op_mini all"
]
}
}
webpack.config.js
//引入
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin")// 引入打包html的插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin") // 提取css
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') // 压缩css
//暴露
module.exports = {
target: "web", // 目标是浏览器
//入口 [以这个文件为入口 开始打包]
entry: "./src/js/index.js",
//出口
output: {
path: path.resolve(__dirname, "dist"), // 要输出的路径 必须是一个绝对路径
filename: "bundle.js", // 输出的文件名,最终打包出来的文件 叫什么名字(bundle)
publicPath: './', // 所有资源的基础路径 静态资源最终访问路
},
//配置
module: {
//规则
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
"css-loader"],
},
//less 打包
{
test: /\.less$/,
// 提取js中的css
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
"css-loader",
"less-loader"
]
},
//css背景图片打包
{
test: /\.(png|jpg|gif)$/,
loader: 'url-loader', // 使用这个loader 处理这种格式的文件
options: { // 写上自己定义的配置
name: '[hash].[ext]', // 输出图片的名字
limit: 10 * 1024, // 限制大小 大于这个值的图片 单独输出 不打包到bundle.js中, 否则打出来的包比较大。小图就直接打包进去,经过base64转码。
esModule: false, // 关闭es6的模块化 全部使用node的模块化
}
},
//HTML引入图片打包
{
test: /\.html$/,
use: ['html-loader'],
},
//字体图标
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
use: ['file-loader'], // 处理这个格式的文件 需要使用哪些loader
},
{
test: /\.js$/,
use: ['babel-loader'], // 处理这个格式的文件 需要使用哪些loader
exclude: /node_modules/, // 排除
}
]
},
// 插件
plugins: [
// 使用插件 这个插件是把 html 打包到 dist 里面
new HtmlWebpackPlugin({
template: "./src/index.html", // 你要以哪个html为模板 进行打包
filename: 'index.html'
}),
// 提取css
new MiniCssExtractPlugin({
filename: "index.css",
}),
// 压缩css
new OptimizeCssAssetsWebpackPlugin()
],
//模式
mode: "production", // 开发模式
// 开发服务器
devServer: {
contentBase: path.resolve(__dirname, 'dist'), // 启动服务器目录
compress: true, // 启动gzip压缩
port: 666, // 端口
open: true // 自动打开服务
},
}
.babelrc
{
"presets": [
"es2015"
]
}
vue-router路由
Vue Router是Vue.js官方的路由管理器。它和Vue.js的核心深度集成, 让构建单页面应用变得易如反掌。包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于Vue js过渡系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的CSS class的链接
- HTML5 历史模式或hash模式, 在IE 9中自动降级
- 自定义的滚动行为
安装
基于第一个vue-cli进行测试学习; 先查看node modules中是否存在vue-router
vue-router是一个插件包, 所以我们还是需要用npm/cnpm来进行安装的。打开命令行工具,进入你的项目目录,输入下面命令。
npm install vue-router --save-dev
# 或
cnpm install vue-router --save-dev
# 或
yarn add vue-router --save-dev
如果在一个模块化工程中使用它,必须要再main.js中通过Vue.use()明确地安装路由功能:
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
// 显示声明使用VueRouter
Vue.use(VueAxios, axios)
测试
-
先删除没有用的东西
-
components
目录下存放我们自己编写的组件 -
定义一个
Content.vue
的组件
<template>
<div>
<h1>内容页</h1>
</div>
</template>
<script>
export default {
name:"Content"
}
</script>
Main.vue
组件
<template>
<div>
<h1>首页</h1>
</div>
</template>
<script>
export default {
name:"Main"
}
</script>
- 安装路由,在src目录下,新建一个文件夹:
router
,专门存放路由,配置路由index.js,如下
import Vue from'vue'
// 导入路由插件
import Router from 'vue-router'
// 导入上面定义的组件
import Content from '../components/Content'
import Main from '../components/Main'
// 安装路由
Vue.use(Router) ;
// 配置路由
export default new Router({
routes:[
{
// 路由路径
path:'/content',
// 路由名称
name:'content',
// 跳转到组件
component:Content
},
{
// 路由路径
path:'/main',
// 路由名称
name:'main',
// 跳转到组件
component:Main
}
]
});
- 在
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,
components: { App },
template: '<App/>'
})
- 在
App.vue
中使用路由
<template>
<div id="app">
<!--
router-link:默认会被渲染成一个<a>标签,to属性为指定链接
router-view:用于渲染路由匹配到的组件
-->
<router-link to="/main">首页</router-link>
<router-link to="/content">内容</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default{
name:'App'
}
</script>
<style></style>
-
在终端输入
npm run dev
运行项目。
注意运行时遇到了版本不兼容问题,Vue和router版本有要求,Vue2和Vue3的代码细节也不一样,因为课程比较老,所有这里降级用来Vue2
vue+elementUI
创建工程
注意:命令行都要使用管理员模式运行
- 创建一个名为hello-vue的工程
vue init webpack hello-vue
。 - 安装依赖, 我们需要安装vue-router、element-ui、sass-loader和node-sass四个插件。
#进入工程目录
cd hello-vue
#安装vue-routern
npm install vue-router --save-dev
#安装element-ui
npm i element-ui -S
#安装依赖
npm install
# 安装SASS加载器
cnpm install sass-loader node-sass --save-dev
#启功测试
npm run dev
- Npm命令解释:
npm install moduleName
:安装模块到项目目录下。npm install -g moduleName
:-g的意思是将模块安装到全局,具体安装到磁盘哪个位置要看npm config prefix的位置。npm install -save moduleName
:–save的意思是将模块安装到项目目录下, 并在package文件的dependencies节点写入依赖,-S为该命令的缩写。npm install -save-dev moduleName
:–save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖,-D为该命令的缩写。
创建登录页面
- 把没有用的初始化东西删掉!
在源码目录中创建如下结构:
-
assets:用于存放资源文件
-
components:用于存放Vue功能组件
-
views:用于存放Vue视图组件
-
router:用于存放vue-router配置
-
创建首页视图,在views目录下创建一个名为Main.vue的视图组件:
<template>
<div>首页</div>
</template>
<script>
export default {
name: "Main"
}
</script>
<style scoped>
</style>
- 创建登录页视图在views目录下创建名为Login.vue的视图组件,其中el-form的元素为ElementUI组件;
<template>
<div>
<el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
<h3 class="login-title">欢迎登录</h3>
<el-form-item label="账号" prop="username">
<el-input type="text" placeholder="请输入账号" v-model="form.username"/>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" placeholder="请输入密码" v-model="form.password"/>
</el-form-item>
<el-form-item>
<el-button type="primary" v-on:click="onSubmit('loginForm')">登录</el-button>
</el-form-item>
</el-form>
<el-dialog
title="温馨提示"
:visible.sync="dialogVisible"
width="30%">
<span>请输入账号和密码</span>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "Login",
data() {
return {
form: {
username: '',
password: ''
},
// 表单验证,需要在 el-form-item 元素中增加 prop 属性
rules: {
username: [
{required: true, message: '账号不可为空', trigger: 'blur'}
],
password: [
{required: true, message: '密码不可为空', trigger: 'blur'}
]
},
// 对话框显示和隐藏
dialogVisible: false
}
},
methods: {
onSubmit(formName) {
// 为表单绑定验证功能
this.$refs[formName].validate((valid) => {
if (valid) {
// 使用 vue-router 路由到指定页面,该方式称之为编程式导航
this.$router.push("/main");
} else {
this.dialogVisible = true;
return false;
}
});
}
}
}
</script>
<style lang="scss" scoped>
.login-box {
border: 1px solid #DCDFE6;
width: 350px;
margin: 180px auto;
padding: 35px 35px 15px 35px;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
box-shadow: 0 0 25px #909399;
}
.login-title {
text-align: center;
margin: 0 auto 40px auto;
color: #303133;
}
</style>
创建路由,在router目录下创建一个名为index.js
的vue-router路由配置文件
import Vue from 'vue'
import Router from 'vue-router'
import Main from '../views/Main'
import Login from '../views/Login'
Vue.use(Router);
export default new Router({
routes:[
{
path:'/login',
name:'login',
component:Login
},{
path: '/main',
name:'main',
component: Main
}
]
});
APP.vue
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
main.js
import Vue from 'vue'
import App from './App'
import router from "./router"
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(router)
Vue.use(ElementUI)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
render:h=>h(App)
})
3.运行项目
- 输入命令
npm run dev