根据B站黑马程序员 VUE教程基础学习
为了毕业设计做准备
Vue基础
- 工具准备
-
- Vue的基本使用步骤
- vue模板语法
-
- `v-cloak`指令用法
- 数据绑定指令
- 数据响应式
- 双向数据绑定
- MVVM设计思想
- 事件绑定
- 事件修饰符
- 按键修饰符
- 案例:简单计算器
-
- 属性绑定
- 样式绑定 class
- style样式处理
- 分支循环结构
- Tab选项卡
- 常用特性
-
- 表单操作
- 自定义指令
- 计算属性
- 过滤器
-
- 使用过滤器格式化日期
- 侦听器
-
- 侦听器案例:验证用户名是否可用
- 生命周期
- 图书管理
- 组件化开发
-
- 组件注册
- 组件命名方式
工具准备
Sublime text 3*链接:Sublime text 3
提取码:5kk5
package controlpackage control
Vue的基本使用步骤
- 需要提供标签用于填充数据
容器<div>
<div id="app">
<div>{{msg}}</div>
</div>
{{}}
插值表达式
;
2. 引入vue.js库文件
在官网上下载开发版的vue.js文件,官网地址:vue;
4. 可以使用vue的语法做功能了
提供一个变量存储vue对象
var vm = new Vue({
el:'#app ',//告诉vue数据填充的位置,#代表id选择器
data:{
msg:'Hello Vue'
}
});
;
5. 把vue提供的数据填充到标签 ;
*[前端渲染]:
vue模板语法
指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达式。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
v-cloak
指令用法
v-cloak
插值表达式会出现“闪动”现象 (刷新时会出现标签之间的内容)
- 提供样式
[v-cloak] {
display: none;
}
-
在插值表达式所在的标签中添加v-cloak指令
背后原理:
先通过样式隐藏内容,然后在内存中进行值的替换,替换好之后再显示最终值
数据绑定指令
-
v-text
填充纯文本
相比插值表达式更简洁
-
v-html
填充Html片段
存在安全问题
本网站内部数据可以使用,来自第三方的数据不可使用
-
v-pre
填充原始信息
显示原始信息,跳过编译过程(分析编译过程)
<div v-text='msg'></div>
<div v-html='msg1'></div>
<div v-pre>{{msg}}</div>
数据响应式
-
html5中的响应式
屏幕尺寸变化导致样式的变化 自适应
-
数据的响应式
数据的变化导致页面样式的变化
-
数据绑定
将数据填充到标签中
-
v-once
只编译一次
显示内容之后不再具有响应式功能
如果显示的信息后续不需要再修改,可以使用,提高性能
双向数据绑定
v-model
控制台和input表单数据改变时页面内容也改变
MVVM设计思想
- M(model)
- V(view)
- VM(view-model)
事件绑定
事件处理:
v-on
指令
- 用法:
v-on:click
- 简写:
事件函数调用方式@click
- 直接绑定函数名称调用:
如果事件直接绑定函数名称,那么默认会传递事件对象作为事件的第一个参数v-on:click='函数名'
- 调用函数:
如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递,并且事件对象必须是v-on:click='say()'
事件函数参数传递$event
- 普通参数传参对象
接收事件对象,function括号中不加美元符$event
事件标签名称event.target.tagName
事件内容event.target.innerHTML
事件修饰符
-
stop
阻止冒泡
冒泡:里层出发的事件会传递到外层,并触发外层事件
-
阻止默认行为,如跳转prevent
- 阻止冒泡函数
event.stopPropagation()‘
- 阻止默认行为
event.preventDefault()‘
按键修饰符
按键后触发事件函数
-
enter
回车键
v-on:keyup.enter
-
delete
删除键
v-on:keyup.delete
-
自定义按键修饰符
全局
对象config.keyCodes
案例:简单计算器
- 通过v-model指令实现数值a和数值b的绑定
- 给计算按钮绑定事件,实现计算逻辑
- 将计算结果绑定到对应位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<h1>简单计算器</h1>
<div>
<span>数值A:</span>
<span>
<input type="text" v-model='a'>
</span>
</div>
<div>
<span>数值B:</span>
<span>
<input type="text" v-model='b'>
</span>
</div>
<div>
<button v-on:click="handle">计算</button>
</div>
<div>
<span>计算结果:</span>
<span v-text="result"></span>
</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{
a:'',
b:'',
result:''
},
methods:{
handle:function(){
//实现计算逻辑
this.result = parseInt(this.a) + parseInt(this.b);
//this.a 和 this.b中得到的是字符串,默认字符串拼接,所以要强制转换
}
}
});
</script>
</body>
</html>
属性绑定
-
双向数据绑定v-bind
的低层实现原理分析 三种实现效果相同v-model
样式绑定 class
- 对象绑定和数组绑定可以结合使用
- Class绑定的值可以简化操作 放在data中的数组或者对象集合
style样式处理
分支循环结构
-
v-if
-
v-else
-
v-else-if
-
v-show
v-if 和 v-show 的区别
- v-if 控制元素是否渲染到页面
- v-show 控制元素是否显示(已经渲染到了页面)
循环结构
v-for
Tab选项卡
最重要的是用
currentIndex
进行判断
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
.tab ul{
overflow: hidden;
padding: 0;
margin: 0;
}
.tab ul li{
box-sizing: border-box;;
padding: 0;
float: left;
width: 100px;
height: 45px;
line-height: 45px;
list-style: none;
text-align: center;
border-top: 1px solid blue;
border-right: 1px solid blue;
cursor: pointer;
}
.tab ul li:first-child{
border-left: 1px solid blue;
}
.tab ul li.active{
background-color: orange;
}
.tab div{
width: 500px;
height: 300px;
display: none;
text-align: center;
font-size: 30px;
line-height: 300px;
border: 1px solid blue;
}
.tab div.current{
display:block;
}
</style>
</head>
<body>
<div id="app">
<div class="tab">
<ul>
<li v-on:click='change(index)' :class='currentIndex==index?"active":""' :key='item.id' v-for='(item,index) in list'>{{item.title}}</li>
</ul>
<div :class='currentIndex==index?"current":""' :key='item.id' v-for='(item,index) in list'>
<img :src="item.path">
</div>
</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{
currentIndex: 0,//选项卡当前的索引
list:[{
id: 1,
title:'apple',
path:'img/apple.jpg'
},{
id: 2,
title:'orange',
path:'img/orange.jpg'
},{
id: 3,
title:'lemon',
path:'img/lemon.jpg'
}]
},
methods:{
change:function(index){
//在这里实现选项卡切换操作
//通过currentIndex操作类名
this.currentIndex = index;
}
}
});
</script>
</body>
</html>
常用特性
表单操作
- Input 单行文本
- textarea 多行文本
- select 下拉多选
- radio 单选框
- checkbox 多选框
表单域修饰符
- number 转化为数值 不再需要强制转换
- trim 去掉开始和结尾的空格
- lazy 将input事件转换为change事件 Input每次输入触发,change每次失去焦点触发(常用于注册用户名验证重复)
自定义指令
第一个参数:指令名称
第二个参数,实现逻辑 el表示指令所绑定的元素
使用时候 v-focus
计算属性
插值表达式里直接写函数名,不需要加()
基于data中的值进行处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<div>{{msg}}</div>
<div>{{reverseString}}</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{
msg:'Hello'
},
computed:{
reverseString:function(){
return this.msg.split('').reverse().join('');
}
}
})
</script>
</body>
</html>
计算属性与方法的区别
- 计算属性基于它们的依赖进行缓存的(依赖:data中数据)
- 方法不存在缓存
- 方法要加括号,计算属性直接用名称不用加括号
- 方法可以传参,计算属性不行
过滤器
格式化数据,比如字符串格式化为首字母大写,将日期格式化为指定的格等。
自定义过滤器可以全局使用
参数级联使用,上一个参数的返回值作为下一个参数的输入值
计算属性不能连续使用,过滤器可以
定义在Vue里,只有在本组件中使用
带参数的过滤器,使用时format接收的参数是从第二个参数开始,第一个参数默认为
data
使用过滤器格式化日期
将时间格式化为yyyy-MM-dd格式
侦听器
数据变化时执行异步或开销较大的操作
侦听器案例:验证用户名是否可用
需求:输入框中输入姓名,失去焦点时验证是否存在,如果已经存在,提示重新输入;如果不存在,提示可以使用。
- 通过v-model实现数据绑定
- 需要提供提示信息
-
需要侦听器监听输入信息的变化
采用侦听器监听用户名的变化
调用后台接口进行验证
根据验证的结果调整提示信息
- 需要修改触发事件
v-model.lazy
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<div>
<span>用户名:</span>
<span> <input type="text" v-model.lazy='uname'>
</span>
<span>{{tip}}</span>
</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{
uname:'',
tip:''
},
methods:{
checkName:function(uname){
//调用接口,可以选用定时任务的方式模拟接口调用
var that = this;//所以先用that缓存this
setTimeout(function(){
//模拟接口调用
//setTimeout中的this是windows
if(uname == 'admin'){
that.tip = '用户名已经存在,请更换一个'
}else{
that.tip = '用户名可以使用'
}
},2000);
}
},
watch:{
uname:function(val){
//调用后台接口验证用户名的合法性
this.checkName(val);
//修改提示信息
this.tip = '正在验证……';
}
},
});
</script>
</body>
</html>
生命周期
主要阶段
图书管理
替换数组返回值一般要赋值给新数组
使用索引修改的数组数据不会显示在页面,响应式
但是使用索引修改的对象数据可以显示在页面,非响应式,控制台修改数据页面也不变化
修改响应式数据可以用于修改数组和对象数据
图书列表
- 实现静态列表效果
- 基于数据实现模板效果
- 处理每行的操作按钮
添加图书
- 实现表单静态效果
- 添加图书表单域数据绑定
- 添加按钮事件绑定
- 实现添加业务逻辑
修改图书
- 修改信息填充到表单
- 修改后重新提交表单
- 重用添加和修改方法
删除图书
- 删除按钮绑定事件处理方法
- 实现删除业务逻辑
箭头函数中的
this
等于定义该函数的父级作用域中的
this
初始表格页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
.grid{
margin:auto;
width: 500px;
text-align: center;
}
.grid table{
width: 100%;
border-collapse: collapse;
}
.grid th,td{
padding: 10;
border: 1px dashed orange;
height: 35px;
line-height: 35px;
}
.grid th{
background-color: orange;
}
.grid .book{
padding-bottom:10px;
padding-top:5px;
background-color: #F3DCAB;
}
</style>
</head>
<body>
<div id="app">
<div class="grid">
<div>
<h1>图书管理</h1>
<div class="book">
<div>
<label for="id">编号</label>
<input type="text" id="id">
<label for="name">名称</label>
<input type="text" id="name">
<button>提交</button>
</div>
</div>
</div>
<table>
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>JavaScript</td>
<td>2018-01-01</td>
<td>删除</td>
</tr>
<tr>
<td>1</td>
<td>JavaScript</td>
<td>2018-01-01</td>
<td>删除</td>
</tr>
<tr>
<td>1</td>
<td>JavaScript</td>
<td>2018-01-01</td>
<td>删除</td>
</tr>
</tbody>
</table>
</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{
id:'',
name:'',
books:[{
id: 1,
name: '三国演义',
date: ''
},{
id: 2,
name: '水浒传',
date: ''
},{
id: 3,
name: '红楼梦',
date: ''
},{
id: 4,
name: '西游记',
date: ''
}]
},
});
</script>
</body>
</html>
完整
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
.grid{
margin:auto;
width: 500px;
text-align: center;
}
.grid table{
width: 100%;
border-collapse: collapse;
}
.grid th,td{
padding: 10;
border: 1px dashed orange;
height: 35px;
line-height: 35px;
}
.grid th{
background-color: orange;
}
.grid .book{
padding-bottom:10px;
padding-top:5px;
background-color: #F3DCAB;
}
.grid .total{
height: 30px;
line-height: 30px;
background-color: #F3DCAB;
border-top: 1px solid #C2D89A;
}
</style>
</head>
<body>
<div id="app">
<div class="grid">
<div>
<h1>图书管理</h1>
<div class="book">
<div>
<label for="id">编号</label>
<input type="text" id="id" v-model="id" :disabled="flag">
<label for="name">名称</label>
<input type="text" id="name" v-model="name">
<button @click="handle" disabled="submitFlag">提交</button>
</div>
</div>
</div>
<div class="total">
<span>图书总数:</span>
<span>{{total}}</span>
</div>
<table>
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr :key='item.id' v-for='item in books'>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date | format('yyyy-MM-dd hh:mm:ss')}}</td>
<td>
<a href="" @click.prevent='toEdit(item.id)'>修改</a>
<!---禁止a标签的默认行为,不会跳转--->
<span></span>
<a href="" @click.prevent='deleteBook(item.id)'>删除</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
Vue.directive('focus', {
inserted: function (el) {
el.focus();
}
});
Vue.filter('format', function(value, arg) {
function dateFormat(date, format) {
if (typeof date === "string") {
var mts = date.match(/(\/Date\((\d+)\)\/)/);
if (mts && mts.length >= 3) {
date = parseInt(mts[2]);
}
}
date = new Date(date);
if (!date || date.toUTCString() == "Invalid Date") {
return "";
}
var map = {
"M": date.getMonth() + 1, //月份
"d": date.getDate(), //日
"h": date.getHours(), //小时
"m": date.getMinutes(), //分
"s": date.getSeconds(), //秒
"q": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
format = format.replace(/([yMdhmsqS])+/g, function(all, t) {
var v = map[t];
if (v !== undefined) {
if (all.length > 1) {
v = '0' + v;
v = v.substr(v.length - 2);
}
return v;
} else if (t === 'y') {
return (date.getFullYear() + '').substr(4 - all.length);
}
return all;
});
return format;
}
return dateFormat(value, arg);
})
var vm = new Vue({
el:'#app',
data:{
flag: false,
submitFlag: false,
id:'',
name:'',
books:[]
},
methods:{
handle:function(){
if(this.flag == true){
//编辑操作
//根据当前的id去更新数组中对应的数据
this.books.some((item) => {
if(item.id == this){
item.name = this.name;
//完成更新操作后,需要终止循环
return true;
}
});
this.flag = false;
}else{
//添加图书
var book = {};
book.id = this.id;
book.name = this.name;
book.date = '';
this.books.push(book);
//清空表单
this.id = '';
this.name = '';
}
//提交成功后清空表单
this.id = '';
this.name = '';
},
toEdit:function(id){
//禁止修改id
this.flag = true;
console.log(id)
//根据id查询要编辑的数据
var book = this.books.filter(function(item){
return item.id == id;
});
console.log(book)
//把获取到的信息填充到表单
this.id = book[0].id;
this.name = book[0].name;
},
deleteBook:function(id){
//删除图书
//根据id从数组中查找元素索引
var index = this.books.findIndex(function(item){
return item.id == id;
});
//根据索引删除数组元素
this.books.splice(index,1);
//方法二:
//通过filter方法进行删除
//排除要删除的剩下就是删除后的内容,所以判断返回id不相等的那部分就是删除后的内容
//this.books = this.books.filter(function(item){
//return item.id != id;
//});
}
},
computed: {
total: function(){
// 计算图书的总数
return this.books.length;
}
},
watch: {
name: function(val) {
// 验证图书名称是否已经存在
var flag = this.books.some(function(item){
return item.name == val;
});
if(flag) {
// 图书名称存在
this.submitFlag = true;
}else{
// 图书名称不存在
this.submitFlag = false;
}
}
},
mounted: function(){
// 该生命周期钩子函数被触发的时候,模板已经可以使用
// 一般此时用于获取后台数据,然后把数据填充到模板
var data = [{
id: 1,
name: '三国演义',
date: 2525609975000
},{
id: 2,
name: '水浒传',
date: 2525609975000
},{
id: 3,
name: '红楼梦',
date: 2525609975000
},{
id: 4,
name: '西游记',
date: 2525609975000
}];
this.books = data;
}
});
</script>
</body>
</html>
组件化开发
组件注册
名称有要求
数据通过return返回值,每个组件数据独立
局部组件只能在注册他的父组件中使用
组件命名方式
如果使用驼峰式命名组件,在使用组件时候,只能在字符串模板中用驼峰的方式使用