插值
就是通过{{}}
插入实例对象对象中 data 的属性值 ,支持表达式(加减乘除等有结果的),尽搞那么专业的词汇
指令
v-text:会替换标签整个内容,{{}}插值方式只替换被扩起的部分,不会解析html内容
v-html:可以渲染html,尽量避免使用,可能会引起xss攻击
v-bind:用来绑定标签上的任何属性,简化语法是:前面的v-bind不用写直接用:
1.动态绑定图片路径
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-text|v-html</title>
</head>
<body>
<div id="app">
<img v-bind:src="src">
</div>
</body>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
src: './postman.png'
}
});
</script>
</html>
2.绑定a标签上的id
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-text|v-html</title>
</head>
<body>
<div id="app">
<img v-bind:src="src">
<a v-bind:href="'del.php?id='+id">删除</a>
</div>
</body>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
src: './postman.png',
id:11,
}
});
</script>
</html>
3.绑定class(有两种语法,对象语法,和数组语法)
对象语法:
如果isActive为true,则返回的结果为 <div id="app" class="active"></div>
<div id="app" v-bind:class="{active: isActive}">
hei
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
isActive: true
}
});
</script>
数组语法
渲染结果: <div id="app" class="active text-danger"></div>
<div id="app" v-bind:class="[activeClass, dangerClass]">
hei
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
activeClass: 'active',
dangerClass: 'text-danger'
}
});
</script>
4.绑定style(有两种语法,对象语法,和数组语法)
对象语法
渲染的结果: <div id="app" style="color: red; font-size: 40px;">hei</div>
<div id="app" v-bind:style="{color: redColor, fontSize: font + 'px'}">
hei
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
redColor: 'red',
font: 40
}
});
</script>
数组语法
渲染结果:<div id="app" style="color: red; font-size: 18px;">abc</div>
<div id="app" v-bind:style="[color, fontSize]">abc</div>
<script>
var vm = new Vue({
el: '#app',
data: {
color: {
color: 'red'
},
fontSize: {
'font-size': '18px'
}
}
});
</script>
简化语法:
<div id="app">
<img v-bind:src="imageSrc">
<!-- 缩写 -->
<img :src="imageSrc">
</div>
v-model:同v-bind一样都是绑定数据,只不过这个是双向绑定,不管 DOM 元素还是 vue 对象,数据的改变都会影响到另一个;
修饰符:
.lazy
- 取代 input
监听 change
事件
.number
- 输入字符串转为有效的数字
.trim
- 输入首尾空格过滤
v-on:绑定事件监听
简写方式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="ids" @click="fun">按钮</button>
</body>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el:'#ids',
data:{
},
methods:{
fun:function () {
console.log(11);
}
}
});
</script>
</html>
用修饰符 阻止浏览器的默认行为
<div id="app">
<a href="http://www.qq.com" @click.prevent="cli">腾百万</a>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
// 将事件处理程序写入methods对象
methods: {
cli: function () {
alert('123');
}
}
});
</script>
使用修饰符绑定一次性事件
<div id="app">
<a href="http://www.qq.com" @click.once="cli($event)">腾百万</a>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
// 将事件处理程序写入methods对象
methods: {
cli: function (ev) {
ev.preventDefault();
alert('123');
}
}
});
</script>
按键修饰符
绑定键盘抬起事件,但是只有enter
键能触发此事件
<div id="app">
<input type="text" @keyup.enter="keyup">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {
keyup:()=>{
console.log('111')
}
}
});
</script>
系统修饰符
按住 shift
后才能触发点击事件
<div id="app">
<input type="button" value="按钮" @click.shift="cli">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {
cli:()=>{
console.log('111')
}
}
});
</script>
鼠标修饰符
鼠标中键触发事件
<div id="app">
<input type="button" value="按钮" @click.middle="cli">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {
cli:()=>{
console.log('111')
}
}
});
</script>
为什么在 HTML 中监听事件?
这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。
它不会导致任何维护上的困难。实际上,使用 v-on
有几个好处:
1.扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
2.因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
3.当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。
v-show:显示和隐藏元素(实际上是通过css样式display:none来控制)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-show</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app" v-show="is_show">111</div>
<script>
var app = new Vue({
el:'#app',
data:{
is_show:true//false 为隐藏
}
});
</script>
</body>
</html>
v-if / v-else / v-else-if 条件判断
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-if</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app">
<div v-if="type == 'A'">A</div>
<div v-else-if="type == 'B'">B</div>
<div v-else="type == 'C'">C</div>
</div>
<script>
var app = new Vue({
el:'#app',
data:{
type:'a'
}
});
</script>
</body>
</html>
v-for:比如经常给一个li循环展示数据,支持数组和对象
<div id="app">
<ul>
<li v-for="(val,key) in arr">{{val}}---{{key}}</li>
</ul>
<ul>
<li v-for="(val,key) in obj">{{val}}---{{key}}</li>
</ul>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
arr: ['a', 'b', 'c'],
obj: { id: 1, name: '李四' }
},
})
</script>
v-clock:解决vue还没被加载之前会出现花括号的方法,平时基本用不上的
<style>
[v-cloak] {
display: none;
}
</style>
<div id="app">
<p v-cloak>{{obj.id}}</p>
</div>
<script src="./vue.js"></script>
<script>
setTimeout(() => {
var vm = new Vue({
el: '#app',
data: {
obj: { id: 1, name: '李四' }
},
})
}, 2000);
</script>
v-once:数据绑定一次
<div id="app">
<p v-once>{{msg}}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg:'kkk'
},
})
</script>
匿名函数最大的用处就是,封装作用域
vue之全选与全不选
思路,其实就是遍历元素,然后把所有元素的状态改成和当前选择框的状态一致
<-- html设置v-model="v.stat" 数据来控制是否显示 -->
<input class="toggle" type="checkbox" v-model="v.stat">
//js点击事件
methods:{
checkall:function (ev) {
console.log(1);
for (let i = 0;i< this.list_data.length;i++){
//这是全选和反选
//this.list_data[i].stat = !this.list_data[i].stat;
//全选和全不选
this.list_data[i].stat = ev.target.checked;
}
}
}
Vue标签template控制数据的显示和隐藏,list_data为你从服务器获取到的数据
<template v-if="list_data.length">
这里是你要隐藏的html部分
</template>
添加任务:
<input v-on:keyup.enter="addToDo" class="new-todo" placeholder="你想要有什么新的计划?" autofocus>
addToDo(ev){
var title = ev.target.value;
var id = 4;
var stat = false;
this.list_data.push({id,title,stat});
}
如果被选中就删除
<li v-for="(v,k) in list_data" v-bind:class="{completed:v.stat}">
删除任务:
给每个li里面的button添加一个事件
<button @click="removeToDo(k)" class="destroy"></button>
js代码:
splice第一个参数,删除的下标,第二个参数,要删除的个数
removeToDo(k){
this.list_data.splice(k,1);
}
删除全部已经选择的项目
1.先给全部删除增加一个点击事件
removeAll(){
//超级精简写法,原理就是谁是false就返回 es6新的语法,只有一个reture的时候可以这么写
this.list_data = this.list_data.filter((v)=>!v.stat);
}
计算属性:缓存数据的作用,减少开销,调用的时候当做一个属性来调用,所以不需要加()号
<script>
var app = new Vue({
el: '#div',
data: {
xing:'',
ming:'',
},
//方法
methods:{
},
//计算属性
computed:{
fulln(){
return this.xing+this.ming+Date.now();
}
}
})
</script>
侦听器:侦听数据的改变,侦听的方法名,要和数据的属性名保持一致,形参一:新值,形参二:旧值
比如异步提交数据验证,验证服务器请求错误时还是用旧的值替换
// 设置侦听器
watch: {
// 侦听器中的方法名和要真挺的数据属性名必须一致
// xing 发生变化,侦听器就会被执行,且将变化后的值和变化前的值传入
xing:function(newVal,old_val){
// this.fullname = newVal+this.ming;
var t = this;
// 在侦听器中执行异步网络请求
$.get('./xx.php',(d)=>{
t.fullname = d;
})
},
}
vue获取节点对象,在某些特殊业务需求的时候来使用ref操作dom,虽然违背mvvm设计原则,但是还是迫不得已要用
<p ref='p'>1</p>
this.$refs.p.innerHTML = '2';
// this.$refs 只是拿到获取节点的工具, 后面跟上标签上ref的值
过滤器:就比如你要过滤掉文本中的敏感词 就可以用这个过滤器
私有过滤器,就是卸载vue实例里面的
var app = new Vue({
el: '#app',
data:{msg:'UP'},
//定义过滤器
filters:{
// 过滤器的名称及方法
myFilters:function(val){
return val.toLowerCase();
}
}
})
全局过滤器,写在外边的
<script>
Vue.filter('myFilters', function (val) {
return val.toLowerCase();
})
// 定义两个全局过滤器
Vue.filter('get3', function (val) {
return val.replace('苍井空','***');
})
// 两个Vue 实例
var app = new Vue({
el: '#app',
data: {
msg: ''
}
})
var app2 = new Vue({
el: '#app2',
data: {
msg: ''
}
})
</script>
自定义指令:分为全局自定义指令和私有自定义指令
全局自定义指令获取焦点:
//input 标签上直接使用新的属性 v-getfocus即可
Vue.directive('getfocus',{
inserted:function (el) {
el.focus();
}
});
局部自定义指令获取焦点
<input @keyup.enter="addTodo" v-getfocus class="new-todo" placeholder="请输入" >
// 注册 局部(私有)指令
directives: {
// 定义指令名称
getfocus: {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
}
},
自定义指令传值:
<p v-color='colors'>这是一段文本</p>
<div id="app">
<p v-color='colors'>自定义指令的使用</p>
</div>
<script>
var app = new Vue({
el: '#app',
data:{
colors:'yellow'
},
// 注册 局部(私有)指令
directives: {
// 定义指令名称
color: {
// 自定义指令可以接受第二个参数
inserted: function (el,val) {
// 第二个参数中包含了指令名称、挂载名称及数据键值
console.log(val);
// 聚焦元素
el.style.color = val.value;
}
}
}
})
</script>
动画以及过度
在项目中,大多情况下,我们会借助第三方 CSS 动画库来实现,如:Animate.css ;
//给要设置动画的标签用transition 包裹
<transition name="fade">
<p v-show="is">我是内容</p>
</transition>
//书写样式
<style>
/* 从有到无 */
/* 开始 */
.fade-leave{
opacity: 1;
}
/* 过程 */
.fade-leave-active
{
transition: opacity 1s;
}
/* 结束 */
.fade-leave-to
{
opacity: 0;
}
.fade-enter{
opacity: 0;
}
.fade-enter-active{
transition: opacity 3s;
}
.fade-enter-to{
opacity: 1;
}
</style>
json-server axios
todo案例重构(json-server 和 axios):
首先是获取到服务器的数据,npm安装 json-server服务
npm install json-server -g
准备db.json文件
{
"list_data": [
{
"id": 1,
"title": "吃饭",
"stat": false
},
{
"id": 2,
"title": "睡觉",
"stat": true
},
{
"id": 3,
"title": "打豆豆",
"stat": false
}
]
}
启动json-server服务
json-server --watch db.js
//在页面中直接引入axios.js文件
var app = new Vue({
el: '#todoapp',
data: {
//默认数据为空
list_data: {}
},
//使用生命周期的钩子函数,请求服务器,获取全部数据
mounted:function(){
axios.get("http://localhost:3000/list_data")
.then((backdata)=>{
this.list_data = backdata.data;
})
},
添加todu任务
//添加todu
addToDo(ev) {
var title = ev.target.value.trim();
if (title == '') {
return;
}
var id = this.list_data.length + 2;
var stat = false;
// 组装数据
var obj_data = {id, title, stat};
//发送请求数据入库
axios.post("http://localhost:3000/list_data",obj_data)
.then((backdata)=>{
let {data,status} = backdata;
if(status == 201){
this.list_data.push(data);
}
});
//todu添加完成时,清空input文本
ev.target.value = '';
},
任务删除
<button @click="removeToDo(k,v.id)" class="destroy"></button>
removeToDo(k,id) {
//发送请求进行删除
axios.delete("http://localhost:3000/list_data/"+id)
.then((backdata)=>{
let {data,status} = backdata;
if(status == 200){
this.list_data.splice(k, 1);
}
});
},
任务完成
<input @click="complateToDo(k,v.id)" class="toggle" type="checkbox" v-model="v.stat">
complateToDo(k,id){
var chestat = !this.list_data[k].stat;
//重新组装新的数据
newdata = {};
newdata.id = id;
newdata.stat = chestat;
newdata.title = this.list_data[k].title;
axios.put("http://localhost:3000/list_data/"+id,newdata)
.then((backdata)=>{
var {data,status} = backdata;
if(status != 200){
// 具体修改任务列表中那个任务的那个数据值
this.list_data[k].stat = chestat;
}
})
}
组件的基本使用
组件的好处:组件是可复用的 Vue 实例,且带有一个名字。把这个组件作为自定义元素来使用。组件的好处是写一次可以进行任意次数的复用,简单理解就是当做一个标签用
写法有全局组件,和局部组件
全局组件:
<div id="app">
<!-- 使用组件 -->
<!-- 将组件名直接当做标签名在html代码中使用即可 -->
<mytemp></mytemp>
<!-- 组件可以进行任意次数的复用 -->
<mytemp></mytemp>
</div>
<script>
// 定义一个名为 mytemp 的新组件
Vue.component('mytemp',{
// template属性的值,作为组件的内容
// vue 会把这个值替换到html中并会被浏览器渲染
template:"<h2>我是一个组件</h2>"
})
var app = new Vue({
el: '#app',
})
</script>
局部组件
<div id="app">
<!-- 使用组件 -->
<!-- 将组件名直接当做标签名在html代码中使用即可 -->
<mytemp></mytemp>
</div>
<div id="app2">
<!-- 不可用 -->
<mytemp></mytemp>
</div>
<script>
var app = new Vue({
el: '#app',
// app 的私有组件,其他实例对象不可用
components: {
mytemp: {
template: "<h2>我是一个组件</h2>",
}
}
})
var app2 = new Vue({
el: '#app2',
})
</script>
组件的使用注意事项
1.组件名如果是驼峰法命名法,大写字母改成小写,然后加一个 -
2.template属性,根标签只有一个
<div id="app">
<!-- 使用组件 -->
<!-- 将组件名直接当做标签名在html代码中使用即可 -->
<my-temp></my-temp>
<!-- 单标签方式使用 -->
<my-temp/>
</div>
<div id="app2">
<!-- 不可用 -->
<mytemp></mytemp>
</div>
<script>
var app = new Vue({
el: '#app',
// app 的私有组件,其他实例对象不可用
components: {
// 驼峰法命名
myTemp: {
// 必须有唯一的根标签,多标签报错
template: "<div><h2>我是一个组件</h2><h3>df</h3></div>",
}
}
})
var app2 = new Vue({
el: '#app2',
})
</script>
组件的小例子
<div id="app">
<tops></tops>
<lefts></lefts>
<rights></rights>
</div>
<script>
var app = new Vue({
el: '#app',
components:{
tops:{
template:'<div class="top">我是顶</div>'
},
lefts:{
template:'<div class="left">我是左</div>',
},
rights:{
template:'<div class="right">我是右</div>'
}
}
})
</script>
vue组件概念
通过new Vue()
可以得到一个实例对象,其实这个实例对象就是一个特殊的组件,也有 template
参数,也可以当做组件来使用;
vue实例对象也是一个组件,而 mytemp
组件就是运行在 实例对象下面的,这时我们也会将 实例对象称为 父组件,将 mytemp
组件称为 子组件;
使用prop向子组件传值
<div id="app">
<mytemp v-bind:cc="msg" v-bind:kk="msg2"></mytemp>
</div>
<script>
var app = new Vue({
el: '#app',
data:{
msg:'数据',
msg2:'数据二'
},
components:{
mytemp:{
template:'<h2>data:{{cc}}<br>{{kk}}</h2>',
props:['cc','kk'],
}
}
})
</script>
生命周期:官网有图式,你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。
路由组件:
<!-- 引入路由 -->
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<div id="app">
<ul>
<li><a href="#/login">登录</a></li>
<li><a href="#/register">注册</a></li>
</ul>
<!-- 路由中设置的组件会替换router-view标签 -->
<router-view></router-view>
</div>
<script>
// 1:定义路由组件
var login = {
template: '<h2>我是登录页面</h2>'
}
var register = {
template: '<h2>注册有好礼</h2>'
}
// 2:获取路由对象
var ro = new VueRouter({
// 定义路由规则
routes: [
// {请求的路径,componet是模板}
{ path: "/register", component: register },
{ path: "/login", component: login },
]
})
var app = new Vue({
el: '#app',
// ES6 属性简写
// 3:将router对象传入Vue
router:ro
})
</script>
官方为我们提供了 router-link
标签 来替换a标签
<li><router-link to="/login">登录</router-link></li>
<li><router-link to="/register">注册</router-link></li>
使用 router-link 的一大好处就是,每当我们点击时,在标签内就会自动帮我们添加 class 属性,而此时,我们就可以利用 class 属性,来定义样式:
<style>
.router-link-active {
color: red;
}
</style>
路由的动态匹配传值
假设有一个用户列表,想要删除某一个用户,需要获取用户的id传入组件内,如何实现呢?
1.通过 <router-link> 传参,在路径上传入具体的值
<router-link to="/users/120">用户管理</router-link>
2.路由规则中增加参数,在path最后增加 :id
{ path: '/users/:id', component: Users },
3.在组件内部可以使用,this.$route 获取当前路由对象
var Users = {
template: '<div>这是用户管理内容 {{ $route.params.id }}</div>',
mounted() {
console.log(this.$route.params.id);
}
};
命令行工具CLI(好用,掌握)
Vue 提供了一个官方的 CLI,为单页面应用 (SPA) 快速搭建繁杂的脚手架。
初始化项目
安装 cli 命令工具:npm install -g @vue/cli @vue/cli-init
安装成功后,使用 vue -V
命令,查看版本号;
使用 vue init webpack myapp
构建一个名为 myapp 的项目:
Vue 依然使用询问的方式,让我们对项目有一个初始化的信息
Project name:项目名
Project description: 项目描述
Author: 作者
Vue build:
第一种:配合大部分的开发人员 √
第二种:仅仅中有runtime
Install vue-router? 是否安装vue-router Y
Use ESLint to lint your code? 这个是检测语法错误的插件,询问是否使用这个插件 Y
Pick an ESLint preser:使用哪种语法规范来检查我们的代码:
Standard: 标准规范 √
Airbnb: 爱彼迎规范
Set up unit test: 设置单元测试 N
Setup e2e tests: 设置端对端测试 N
Should we run 'npm install':要不要帮忙你下载这个项目需要的第三方包
使用npm来下载 √
使用yarn来下载
To get started:
cd myapps
npm run dev // 使用命令启动项目
-----
Your application is running here: http://localhost:8080
打开浏览器,访问 http://localhost:8080
看到浏览器的欢迎界面,表示项目运行成功
到这里一个前端项目就搭建完成了
项目解构介绍
语法检测:
如果我们在 构建项目时 选择了 Use ESLint to lint your code
那么我们在写代码时必须严格遵守 JavaScript Standard Style 代码风格的语法规则
使用两个空格 – 进行缩进
字符串使用单引号 – 需要转义的地方除外
不再有冗余的变量 – 这是导致 大量 bug 的源头!
行首不要以 (
, [
, or ``` 开头
这是省略分号时唯一会造成问题的地方 – 工具里已加了自动检测!
关键字后加空格 if (condition) { ... }
函数名后加空格 function name (arg) { ... }
坚持使用全等 ===
摒弃 ==
一但在需要检查 null || undefined
时可以使用 obj == null
。
一定要处理 Node.js 中错误回调传递进来的 err
参数。
使用浏览器全局变量时加上 window
前缀 – document
和 navigator
除外
避免无意中使用到了这些命名看上去很普通的全局变量, open
, length
, event
还有 name
。
代码项目规范
(1)严格模式: 百度吧,一堆
(2)ES6模块化
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用;
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口;
ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";
;
ES6 模块之中,顶层的this
指向undefined
;CommonJS 模块的顶层this
指向当前模块;
项目的一整个流程