概述
Vue.js
作者
尤雨溪
本科:室内艺术和艺术史
硕士:美术设计和技术
硕士期间,偶然接触到了 JavaScript。
因为浓烈的兴趣,开发了目前前端三大框架之首的 Vue.js(另外两个分别是 Angular.js 和 React.js)
他的经历完美的印证了这句话:兴趣是最好的老师。
概念
一款用于构建用户界面的渐进式 JavaScript 框架。
渐进式:Vue渐进式-先使用Vue的核心库,再根据你的需要的功能再去逐渐增加加相应的插件。
采取关注度分离原则(SOC),核心库只关注视图层(名称发音 View 的由来),其他功能由相应插件完成。
- Axios:页面通信。
- router:页面跳转。
- Babel:编译工具,兼容浏览器 ES 版本。
- WebPack:打包、压缩。
官网
https://cn.vuejs.org/v2/guide/
由于是 Vue 是中国人写的,官方文档很符合中国人的理解逻辑,看起来相对轻松。
Node.js
2009年发布。
一套 JavaScript 运行环境,类似于 JDK。
npm:项目综合管理工具,类似于 Maven。
yarn:npm 的替代方案,类似于 Maven 和 Gradle 的关系。
Node.js 的作者已经声称放弃 Node.js,说是架构做的不好再加上笨重的 node_modules,开始开发全新架构的 Deno(destroy node)。
nvm
nvm 全名 node.js version management,一个 Node.js 的版本管理工具。
通过它可以安装和切换不同版本的 Node.js 。
ElementUI
饿了么推出的基于 Vue 的桌面端组件库。
Vue 2.0 和 3.0 各有对应的组件库。
组件以 el-
开头。
组件查询:https://element.eleme.cn/
环境搭建
- 安装 nvm-setup.exe(Node.js 版本管理工具)。
- 转到安装目录下(默认目录为 C:\Users\Administrator\AppData\Roaming\nvm)。
- 运行命令:
nvm install 版本号
(安装指定版本的 Node.js)。 - 运行命令:
nvm use 版本号
(使用指定版本的 Node.js)。
部署运行
在项目下运行
npm i
。
npm i
不仅仅是npm install
的简写,也存在一定的区别:
npm i
安装的模块无法用 npm uninstall
删除,用 npm uninstall i
才卸载掉。
npm i
会帮助检测与当前 node 版本最匹配的 npm 包版本号,并匹配出来相互依赖的 npm 包应该提升的版本号。
npm intall
安装报错时肯定会出现 npm-debug.log 文件,npm i
不一定。
初始化推荐
npm i
,后续安装推荐npm install
。
前端项目目录下运行命令
npm run dev
:普通启动。npm run start
:start 执行的就是 dev 的脚本,与上个命令效果一致。npm run start:support
:热部署启动,推荐。
基础语法
带有前缀 v-
的指令,表示它们是 Vue 提供的特殊特性。
v-bind
绑定元素(单向绑定)。
<body>
<div id="app">
<h1 v-bind:title="message">标题</h1>
<!-- v-bind 指令的简写形式: 冒号(:) -->
<h1 :title="message">标题</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})
</script>
</body>
v-if
条件判断语句
<body>
<div id="app">
<!--=== 三个等号在 JS 中表示绝对等于(就是数据与类型都要相等) -->
<h1 v-if="type === 'A'">A</h1>
<h1 v-else-if="type === 'B'">B</h1>
<h1 v-else-if="type === 'C'">C</h1>
<h1 v-else>who</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
type: 'A'
}
})
</script>
</body>
v-for
循环语句
<body>
<div id="vue">
<li v-for="item in items">
{ { item.message } }
</li>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script><script>
var vm = new Vue({
el: '#app',
data: {
//数组
items: [
{message: 'Vue.js'},
{message: 'Node.js'}
]
}
});
</script>
</body>
items 是数组,item是数组元素迭代的别名。
这里和 Thymeleaf 的语法十分相似。
v-on
监听事件
<body>
<div id="app">
<!-- v-on 绑定了 click 事件,并指定了名为 sayHi 的方法 -->
<button v-on:click="sayHi">单击</button>
<!-- v-on 指令的简写形式 @ -->
<button @click="sayHi">单击</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: { message: 'Hello World' },
// 方法必须定义在 Vue 实例的 methods 对象中
methods: {
sayHi: function (event) {
// `this` 在方法里指向当前 Vue 实例
alert(this.message);
}
}
});
</script>
</body>
v-model
双向绑定
数据发生变化的时候,视图跟着变化。
视图发生变化的时候,数据跟着变化。
<body>
<div id="app">
<!-- v-bind:value只能进行单向的数据渲染 -->
<input type="text" v-bind:value="searchMap.keyWord">
<!-- v-model 可以进行双向的数据绑定 -->
<input type="text" v-model="searchMap.keyWord">
<p>绑定数据:{ { searchMap.keyWord } }</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
searchMap:{
keyWord: 'kuangshen'
}
}
})
</script>
</body>
用浏览器打开以上代码可以看到
改变 v-bind 绑定的输入框的值,下方的值不会改变。
改变 v-model 绑定的输入框的值,下方的值会改变。
组件
<body>
<div id="app">
<ul>
<my-component-li v-for="item in items" v-bind:item="item"></my-component-li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script>
// 先注册组件
Vue.component('my-component-li', {
props: ['item'],
template: '<li>Hello { {item} }</li>'
});
// 再实例化
Vue var vm = new Vue({
el: '#app',
data: {
items: ["张三", "李四", "王五"]
}
});
</script>
</body>
v-bind:item="item":将遍历的 item 项绑定到组件中 props 定义的名为 item 属性上。
= 号左边的 item 为 props 定义的属性名,右边的 item 为 item in items 中遍历的 item 项的值。
计算属性
一个能够将计算结果缓存起来的属性。
<body>
<div id="app">
<!--注意,一个是方法,一个是属性-->
<p>调用当前时间的方法:{ {currentTime1()} }</p>
<p>当前时间的计算属性:{ {currentTime2} }</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script>
var vue = new Vue({
el: '#app',
data: {
message: 'Hello Vue'
},
methods: {
currentTime1: function () {
return Date.now();
}
},
// 存放计算属性
computed: {
// currentTime2 ,这是一个属性,不是方法
currentTime2: function () {
this.message;
return Date.now();
}
}
})
</script>
</body>
methods 和 computed 里的东西不能重名。
调用 methods 中的方法需要带括号。
调用 computed 中的属性不需要带括号。
如果在 computed 中的方法值发生了变化,则缓存就会刷新。
调用方法时,每次都需要进行执行,调用计算属性可以将计算结果进行缓存,节约我们的系统开销。
可以将不经常变化的计算结果放入计算属性中。
插槽
举例:制作一个待办事项组件(todo),该组件由待办标题(todo-title)和待办内容(todo-items)组成,但这三个组件又是相互独立的。
定义一个名为 todo 的待办事项组件。
<todo></todo>
<script type="text/javascript">
// 定义一个待办事项的组件
Vue.component('todo', {
template: '<div>' +
'<slot name="todo-title"></slot>' +
'<ul>' +
'<slot name="todo-items"></slot>' +
'</ul>' +
'</div>'
});
</script>
定义一个名为 todo-title 的待办标题组件。
<todo-title></todo-title>
<script type="text/javascript">
Vue.component('todo-title', {
props: ['title'],
template: '<div>{ { title } }</div>'
});
</script>
定义一个名为 todo-items 的待办内容组件。
<todo-items></todo-items>
<script type="text/javascript">
Vue.component('todo-items', {
props: ['item', 'index'],
template: '<li>{ {index + 1} }. { {item} }</li>'
});
</script>
组装
<body>
<div id="app">
<todo>
<todo-title slot="todo-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>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
todoItems: ['待办内容1', '待办内容2', '待办内容3']
}
})
</script>
</body>
自定义事件
this.$emit('自定义事件名', 参数)
在vue的实例中,增加一个名为 removeTodoItems 的方法
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" title="待办标题"></todo-title>
<todo-items slot="todo-items" v-for="(item, index) in todoItems"
v-bind:item="item" v-bind:index="index"
v-on:remove="removeTodoItems(index)">
</todo-items>
</todo>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
todoItems: ['待办内容1', '待办内容2', '待办内容3']
},
methods: {
// 该方法可以被模板中自定义事件触发
removeTodoItems: function (index) {
console.log("删除 " + this.todoItems[index] + " 成功");
// splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目
// 其中 index 为添加/删除项目的位置,1 表示删除的数量
this.todoItems.splice(index, 1);
}
}
})
</script>
</body>
修改 todo-items 待办内容组件的代码,增加一个删除按钮,并且绑定事件。
<todo-items></todo-items>
<script type="text/javascript">
Vue.component('todo-items', {
props: ['item', 'index'],
template: '<li>{ {index + 1} }. { {item} }</li><button @click="remove_component">删除</button>',
methods: {
remove_component: function (index) {
// 这里的 remove 是自定义事件的名称,需要在 HTML 中使用 v-on:remove 的方式指派
this.$emit('remove', index);
}
}
});
</script>
调用逻辑
@click="remove_component"
==> this.$emit('remove', index);
==> v-on:remove="removeTodoItems(index)"
路由
主要用于页面跳转。
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- <router-link> 默认会被渲染成一个 <a> 标签,通过传入 to 属性指定链接 -->
<router-link to="/student">学生管理</router-link>
</p>
<!-- 路由出口,路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
<!--资源导入顺序不能颠倒-->
<script src="./lib/vue.min.js"></script>
<script src="./lib/vue-router.min.js"></script>
<script>
// 1. 定义(路由)组件。
// 复杂的组件也可以从独立的vue文件中引入
const Student = { template: '<div>student list</div>' }
// 2. 定义路由
// 每个路由应该映射一个组件。
const routes = [
{ path: '/student', component: Student }
]
// 3. 创建 router 实例,然后传 routes 配置
const router = new VueRouter({
routes // (缩写)相当于 routes: routes
})
// 4. 创建和挂载根实例,从而让整个应用都有路由功能
new Vue({
el: '#app',
router
})
</script>
Axios
由于 Vue.js 是一个视图层框架,所以并不包含 Ajax 的通信功能。
为了解决通信问题,作者单独开发了一个名为 vue- resource 的插件。
不过 2.0 版本以后停止了对该插件的维护并推荐了 **Axios **框架。
Axios 的功能用 jQuery 也可以实现,但因为它操作后台太频繁,更推荐使用 Axios。
创建一个名为 data.json 的文件,放在项目的根目录下。
{
"name": "狂神说Java",
"url": "https://blog.kuangstudy.com",
"page": 1,
"address": {
"street": "洪崖洞",
"city": "重庆市",
"country": "中国"
}
}
编写页面代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<body>
<div id="vue">
<div>名称:{ {info.name} }</div>
<div>地址:{ {info.address.country} }-{ {info.address.city} }- { {info.address.street} }</div>
<div>
链接:<a v-bind:href="info.url" target="_blank">{ {info.url} }</a>
</div>
</div>
<!--引入 JS 文件-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#vue',
data() {
return {
info: {
name: null,
address: {
country: null,
city: null,
street: null
},
url: null
}
}
},
//钩子函数
mounted() {
axios.get('data.json').then(response => (this.info = response.data));
}
});
</script>
</body>
</html>
在 data 中的数据结构必须要和 Ajax 响应回来的数据格式匹配。
目录结构
- build 和 config:WebPack 配置文件
- node_modules:用于存放 npm install 安装的依赖文件
- src: 项目源码目录
- static:静态资源文件
- .babelrc:Babel 配置文件,主要作用是将 ES6 转换为 ES5
- .editorconfifig:编辑器配置
- eslintignore:需要忽略的语法检查配置文件
- .gitignore:git 忽略的配置文件
- .postcssrc.js:css 相关配置文件,其中内部的 module.exports 是 NodeJS 模块化语法
- index.html:首页,仅作为模板页,实际开发时不使用
- package.json:项目的配置文件
- name:项目名称
- version:项目版本
- description:项目描述
- author:项目作者
- scripts:封装常用命令
- dependencies:生产环境依赖
- devDependencies:开发环境依赖