VUE 基础
VUE
文档
官方 文档 https://cn.vuejs.org/ or vue.js
使用版本 最新稳定版本:2.5.21
https://www.cnblogs.com/liwenzhou/p/9959979.html
vue的使用
-
下载 vue.js 文件 引入 或使用网络 链接导入
<!--第一步:引入vue,Vue function--> <script src="./statics/vue.min.js"></script> <!--网路链接 --> <!-- 开发环境版本,包含了有帮助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <!-- 生产环境版本,优化了尺寸和速度 --> <script src="https://cdn.jsdelivr.net/npm/vue"></script>
-
声明领地(Vue实例的作用范围)
使用 id 来定义 作用范围 名字随意
<!--第二步:声明领地(Vue实例的作用范围)-->
<div id="app" >
</div>
-
创建一个对象(Vue对象)
<script> // 第三步:创建一个对象(Vue对象) new Vue() </script>
-
查找领地(作用域)
el : '#app', 查找作用域 app 必须写# 号
<script> new Vue({ // 第四步:查找领地(作用域) el: "#app", data: { xxxx: "hello world" } }) </script>
-
基本使用
<body> <!--第二步:声明领地(Vue实例的作用范围)--> <div id="app"> <p>{{ content + content }}</p> 支持 拼接 字符串 <p>{{ '今晚去我家' }}</p> 直接显示 <p>{{ {'name': "鑫姐" } }}</p> 显示 object 对象 <p>{{ 1 > 2 ? "大于" : "傻逼" }}</p> 三元运算 <p>{{ python + linux }}</p> 数字相加 <p>{{ totalScore }}</p> 函数调用 <p>{{ list }}</p> 显示 </div> <script> // 创建一个对象(Vue对象) new Vue({ // 查找作用域 领地 el: "#app", // 定义 数据 字典的形式 data: { content: "hello", python: 88, linux: 76, list: ['抽烟', '喝酒', '烫头'], }, // 定义方法 函数 尽量不在 页面中做过多的运算 computed: { // 定义函数 totalScore: function () { return this.python + this.linux; }, } }) </script> </body>
vue.js 指令系统
- 指令以v-开头,用来操作标签的文本值,操作标签的属性,绑定事件
操作标签的文本值
-
v-text 渲染文本值
<div id='app' v-text='xxx'></div>
-
v-html 渲染原始标签
<div id='app' v-html='xxx'></div>
-
v-for: 处理丰富的数据结构
<div id='app'> <ul> <li v-for='(value, index) in list' :key='index'>{{ value }}</li> </ul> </div>
-
v-if, v-else-if, v-else: 判断标签是否显示
实现方式:
v-if底层采用的是appendChild removeChild 来实现的
<div v-if="boo==='男'"> <p>滚</p> </div> <div v-else-if="boo==='女'"> <p>来啦老妹</p> </div> <div v-else> <p>没有美女来吗</p> </div> boo 在 data 中定义
-
v-show:判断标签是否显示
实现方式:
v-show通过样式的display控制标签的显示
<div v-show="show"> 显示 </div> show:true, hide:false,
-
v-if和v-show的性能比较 开销问题
-
渲染的开销
v-if:低
v-show:高
-
切换的开销
v-if:appendChild, removeChild 高
v-show:低
-
-
一般来说,v-if有更高的切换开销,而v-show有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show较好,如果在运行时条件很少改变,则使用v-if较好。
操作标签的属性
(class,href,src)
v-bind
简写 :class='aaa' 绑定
绑定类名
<div v-bind:class="aaa">
</div>
aaa:'box1', box1 为类名 必须通过 data 中的变量传输
bbb:'box2',
<div v-bind:class="{ aaa: boo, box1: 1<2 }">
<!-- 通过判断布尔值 来判断是否设置 此类名
</div>
绑定 href 链接地址
<div v-for="(item, index) in lis_links" :key="index">
<a v-bind:href="item.http"><span>{{item.name}}</span></a>
</div>
boo: true,
lis_links: [
{http: 'http://www.baidu.com', name: '百度'},
{http: 'http://www.jd.com', name: '京东'},
{http: 'http://www.taobao.com', name: '淘宝'},
],
<script v-bind:src="path">
</script>
小结:对于属性的操作,一定是通过动态的数据来进行增加或者删除的
v-on 绑定事件
简写 @click='function'
<div id='app'>
<!--给输入框 绑定 回车事件 -->
<input type='text' @keyup.enter='enter' value=''/>
<!--给按钮 绑定 点击事件 -->
<button v-on:click='func' ></button>
</div>
<script>
new Vue({
el: '#app',
data:{},
methods:{
func:function(){
console.log('点击我就会执行')
},
enter:function(){
console.log('回车我就执行!')
},
}
})
</script>
-
修饰符
// 可以阻止form表单的 默认提交 请求 执行 mySubmit 事件 @click.prevent="mySubmit"
v-model='function' 双向数据绑定
<div id='app'>
<input type='text' v-model='message'/>
<p>
输入的值 : {{ message }}
</p>
</div>
- 双向 数据绑定装饰 修饰符
- v-model.number -->> 只能 输入 数字
- v-model.number.lazy -->> 懒加载 输入完毕 离开时 加载
<input type="text" vmodel.number="python">
<input type="text" vmodel.number.lazy="python">
自定义指令
-
遇到一些复杂的需求,vue提供的指令不能完美的处理,有时候我们需要自定义指令,针对这一需求,vue提供了自定义指令,如下所示:
<div id="app"> <div class="box" v-pos.right.bottom="post"></div> <input type="text" v-focus="aaa"> </div> <script> // directive就是vue实现指令系统的后台的功能函数 Vue.directive("pos", function (el, binddings) { // console.log(binddings); 自定义 指令 的所有参数 // binddings.value 就是 post 的 值 为 true 通多 vue 实例 数据传递过来的 if (binddings.value) { // 设置 标签的 属性 style='position: fixed' 绝对定位 el.style.position = "fixed"; // 自定义 指令 v-pos.right.bottom="post" 传递的 属性 样式 right bottom console.log(binddings.modifiers); //{right: true, bottom: true} 是一个字典 值默认 为 true for (let key in binddings.modifiers) { el.style[key] = 0; } } else { // 如果 判断为空 则 不设置 指令 el.style.position = 'static'; } }); // 注册 一个全局自定义 指令 v-focus Vue.directive('focus', { // 将绑定的元素插入到 DOM 中 inserted: function (el, items) { // items 自定义 指令 的所有参数 console.log(items.value); console.log(el, items); // 聚焦元素 el.focus() } }); new Vue({ el: '#app', data: { // 自定义 指令的 开关 post: true, // aaa: 11111, } })
vue实例 中的属性
-
el: '#app' 查找作用域
-
data:
- 定义 数据 或者变量
data: { name: 'zhangziyi', h1: '<h1>zhangziyi</h1>', lis: ['张', '只', '阿斯蒂芬', '号啊'], boo: '女', show: true, hide: false, aaa: 'box1', lis_links: [ {http: 'http://www.baidu.com', name: '百度'}, {http: 'http://www.jd.com', name: '京东'}, {http: 'http://www.taobao.com', name: '淘宝'}, ], },
-
computed: 计算属性
- 计算属性用来监听多个数据,每次页面加载,计算属性中的函数立即执行,但是只要原数据不被修改,那么,就不会触发重新计算,计算属性会使用计算后的缓存结果,只当原数据修改时,才会重新计算并将结果缓存起来。计算属性的计算结果可以当做data中的数据一样使用。
new Vue({ el:'#app', data:{ python: 90, linux: 80, java: 50, }, computed: { sum: function () { return this.python + this.linux + this.java } }, })
-
watch:侦听属性
- 计算属性用来监听多个属性,我们也可以使用它来监听一个属性,但是页面加载即执行计算并不符合我们的需求,如何只在数据被修改后出发相应事件,vue提供给我们的是watch,即侦听属性。
- 侦听属性必须是data中的已存在的数据。
watch:{ python:function (v,k) { console.log(v,k); console.log('改变成绩'); } },
计算属性和方法的区别
方法每次都执行
计算属性的数据没变就直接使用之前的结果
计算属性和侦听器的区别
侦听器适用于那些
当某个值发生变化之后,我就要做什么事情 这种场景!
其他的场景都用计算属性就可以了
-
计算成绩的Demo
- 用到 :
- 双向数据绑定
- 装饰符 修饰符
- 计算属性
- 侦听属性
<div id='app'> <table border="1px"> <thead> <tr> <th>科目</th> <th>成绩</th> </tr> </thead> <tbody> <tr> <td>python</td> <td><input type="text" v-model.number.lazy="python"></td> </tr> <tr> <td>linux</td> <td><input type="text" v-model.number.lazy="linux"></td> </tr> <tr> <td>java</td> <td>{{java}}</td> </tr> <tr> <td>总成绩</td> <td>{{ sum }}</td> </tr> </tbody> </table> </div> <script> new Vue({ el: '#app', data: { python: 90, linux: 80, java: 50, }, computed: { sum: function () { return this.python + this.linux + this.java }}, watch:{ python:function (v,k) { console.log(v,k); console.log('改变成绩'); }},})
- 用到 :
-
methods:{func_1:function(){-----},} 方法 事件绑定时触发
<style> .box1{ background-color: red; } .box2{ background-color: green; } </style> <div id='app'> <span :class="aaa">小马哥</span> <p> <button v-on:click="color">点击</button> </p> </div> methods: { // 点击时执行 此方法 color: function () { if (this.aaa === "box1") { this.aaa = 'box2' } else { this.aaa = 'box1' } } },
获取 DOM
-
$refs
- 要 查找的标签 中 要设置 ref ='' 的 属性
- 在 vue 的 实例中 用 this.$refs 来 获取对应的 标签 .style 设置样式
<div id="app"> <div ref="myRef"><h1>小马哥</h1></div> <button @click="changeColor">点击让小马哥变绿</button> </div> <script> new Vue({ el: "#app", data: { post: true }, methods: { changeColor: function () { // $refs 获取 dom 对象 的 myRef // 标签中 设置 ref='myRef' 的 属性 this.$refs.myRef.style.color = 'green'; } } }) </script>
axios 上传文件:
// 通过file来选择需要上传的文件
<input type="file" class="file">
var formData = new FormData() // 声明一个FormData对象
var formData = new window.FormData() // vue 中使用 window.FormData(),否则会报 'FormData isn't definded'
// 'userfile' 这个名字要和后台获取文件的名字一样;
//'userfile'是formData这个对象的键名
formData.append('userfile', document.querySelector('input[type=file]').files[0])
var options = { // 设置axios的参数
url: '请求地址',
data: formData,
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
}
}
this.axios(options).then((res) => {}) // 发送请求
ES6 中 的常用语法
- var let const
全局变量 有变量提升的的问题
var a = '11'
局部变量 有作用域的变量
let a = '11'
一般定义常量 不可以改变 值
const AA = '121'
-
模板字符串
用 `` 反引号 在 js 中 写html 便签
-
单体函数 foo( )
// 单体函数就是指在Object里面定义普通函数的简写形式 let obj = { foo:function () { // 原始函数 }, foo(){ // 简写 形式 console.log(this); }, };
-
箭头函数 () => {};
function Vue(obj) { this.foo = obj.foo; this.bar = obj.bar; this.foo(); obj.foo(); this.bar(); obj.bar() } let obj = { username: 'zhangziyi', foo(){ console.log(this); }, // 箭头函数的this指向调用该函数的对象的父作用域 bar: () => { console.log(this); } }; // 普通函数的this指向调用该函数的对象 // obj.foo(); new Vue(obj);
todoList
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="static/bootstrap-3.3.7/css/bootstrap.min.css">
</head>
<script src="static/vue.min.js"></script>
<style>
.box {
margin-top: 10px;
/*background-color: #7147ff;*/
}
</style>
<body>
<div id="app">
<div class="container">
<div class="row">
<div class="box col-lg-8 col-lg-offset-2">
<div class="panel panel-primary">
<div class="panel-heading">输入</div>
<div class="panel-body">
<div>
<form action="javascript:void (0)">
<p>输入:>>>{{ message }}</p>
<div class="form-group col-lg-11 pull-left">
<input class="form-control" type="text" v-model="message">
</div>
<button v-on:click="aaa" class="btn btn-sm btn-success">提交</button>
</form>
</div>
</div>
<div class="row">
<div class="col-lg-5 col-lg-offset-1">
<div class="panel panel-default" style="height: 400px;">
<div class="panel-heading">Left</div>
<div class="panel-body">
<ul>
<li v-for="(item,index) in left" :key="index" v-on:click="left_on(index)">
{{item}}
</li>
</ul>
</div>
</div>
</div>
<div class="col-lg-5 ">
<div class="panel panel-default" style="height: 400px;">
<div class="panel-heading">Right</div>
<div class="panel-body">
<ul>
<li v-for="(item,index) in right" :key="index" v-on:click="right_on(index)">
{{item}}
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
left: ['左边'],
right: ['右边'],
message: '',
},
methods: {
aaa: function (asss) {
if (this.message) {
this.left.push(this.message);
console.log(111111111111111);
this.message = ''
}
},
left_on: function (index) {
this.right.push(this.left[index]);
this.left.splice(index, 1);
// event.currentTarget.checked = false;
// // 根据索引找到对应的值
// let things = this.left.splice(index, 1)[0]; // []
// this.right.push(things);
},
right_on: function (index) {
this.left.push(this.right[index]);
this.right.splice(index, 1);
},
}
})
</script>
</body>
</html>
组件
组件注意事项:
- is标识 ==》 table里面只认识tr标签不认识你写的组件
- 组件中的data必须是函数!!!保证每个组件内部的数据都是独立的!
-
实现页面布局的vue的一个非常重要的核心功能
组件只是vue里面的概念,浏览器没有这个概念
组件里面肯定会包含标签
组件里面可能会包含数据
组件里面可能还有事件
综上:组件其实就是一个可复用的Vue实例
-
声子=》挂子=>用子
-
全局组件
注册全局组件
Vue.component(组件的名字,{组件实例})
<div id="app"> <my-button></my-button> <my-button></my-button> </div> <script> Vue.component('my-button', { template: `<button v-on:click="add">{{ message }}</button>`, data: function () { return { message: 0, } }, methods: { add() { this.message++ } } }); new Vue({ el: '#app', }) </script>
-
局部组件
<div id="app"> <my-button></my-button> <my-button></my-button> <my-button></my-button> </div> <script> new Vue({ el: '#app', // 创建局部组件 components: { // 注册 局部组件 以及指定名字 'my-button': { template: `<button v-on:click="add">{{ message }}</button>`, // 组件中的 data 必须 是 function 返回 对象 data: function () { return { message: 0, } }, methods: { add() { this.message++ } } }, } }) </script>
分开的 写法
- 创建局部组件
let myHeader = { template: ` <div> <h1>这是首页</h1> </div> ` }
- 在vue 实例中 注册 组件
new Vue({ el: "#app", components: { // key是自定义的名称,value是创建的局部组件名称 "my-header": myHeader, } })
- 在Vue根实例的作用域中使用局部组件
<div id="app"> <my-header></my-header> </div>
组件间的使用
子组件 let myHeader = { template: ` <div> <h1>我是导航栏</h1> </div> ` } 父组件 let Container = { // 使用子组件 template: ` <div> <my-header></my-header> </div> `, // 注册子组件 components: { "my-header": myHeader } } new Vue({ el: "#app", components: { "container": Container } })
父子 组件之间的数据传递
-
父-->子 之间的 传递
-
在父组件中通过
v-bind:变量名='变量'
传递数据在子组件中通过
props
声明需要被接收的参数
<div id="app"> <app-container></app-container> </div> <script> // 1. 在 父组件 里面的 子组件 中绑定一个自定义属性 let Container = { template: ` <div> <app-header v-bind:fatherData="info"></app-header> </div> `, data(){ return { info: "传递的数据!!!" } }, components: { 'app-header': Header, } }; // 2. 在子组件中使用props接收这个数据 let Header = { template: ` <div> {{ fatherData }} </div> `, props: ['fatherData'], data(){ return { name:"hahaha", } } }; new Vue({ el: '#app', components: { 'app-container': Container } }) </script>
-
-
子--> 父 组件之间的数据传递
-
抛出的事件(不推荐直接在组件里修改根实例的数据)
子组件中通过
$emit
('自定义事件名') 向外抛出自定义事件父组件中用过
v-on:自定义事件名=动作函数
监听子组件抛出的事件
<div id="app"> <app-container></app-container> </div> <script> // 1. 在子组件中使用this.$emit("change-size", 1) 抛出一个自定义事件 let Header = { template: ` <div> <button v-on:click="changeSize">点击修改父组件的字体大小</button> </div> `, methods: { changeSize: function () { // 第一个参数是 自定义事件的 名称 第二个参数是 要传递的 内容 // 从 父组件的 事件 函数中 接受 this.$emit("change-size", 1); } } }; // 2. 在父组件的子组件中绑定抛出的自定义事件 let Container = { template: ` <div> <app-header v-on:change-size="add"></app-header> <span :style="{ fontSize: Size + 'px' }">苦海</span> </div> `, data(){ return { Size: 26, } }, methods:{ add:function(data){ consol.log(data) this.Size++ } } components: { 'app-header': Header, } }; new Vue({ el: '#app', components: { 'app-container': Container } })
-
组件间 传值
-
借助一个空的Vue对象实现组件间通信
let bus = new Vue(); // 大项目用这个 VueX 保存数据
传值的那个组件:
let B = { template: ` <div> <h1>这是 子组件: my-mjj </h1> <button v-on:click="add">选我</button> </div> `, data(){ return { num: 0 } }, methods: { add(){ this.num += 1; // 利用bus对象抛出一个自定义事件 bus.$emit('xuanwo', this.num); } } };
接收值的那个组件:
let A = { template: ` <div> <h1>这是 子组件: my-alex </h1> <p>my-mjj被选中的次数:{{ num }}</p> </div> `, data() { return { num: 0 } }, mounted(){ // 在文档准备就绪之后就要开始监听bus的事件 bus.$on 是否触发了 xuanwo 的事件 bus.$on('xuanwo', (val)=> { // val 就是传递的参数 // this.num += 1; // ? console.log(val); console.log(this); // this 是组件A this.num = val; }) } };
组件系统 混入
vue 中的 代码 重复 问题
mixins:[xxx,xxxx] 组件中 定义 将重复 的 内容提取 可设置多个
let xxxx = {
methods: {
show: function (name) {
console.log(`${name}`);
},
hide: function (name) {
console.log(`${name}`);
}
}
};
let xiaoMa = {
template: `
<div>
<button v-on:click="show('xiaoma_show')">欢迎小马哥过来视察工作</button>
<button v-on:click="hide('xiaoma_hide')">欢迎小马哥下次再来</button>
</div>
`,
mixins: [xxxx,]
};
let chaoGe = {
template: `
<div>
<button v-on:click="show('chaoge_show')">欢迎超哥过来视察工作</button>
<button v-on:click="hide('chaoge_hide')">欢迎超哥下次再来</button>
</div>
`,
mixins: [xxxx]
};
new Vue({
el: "#app",
components: {
'xiaoma': xiaoMa,
'chaoge': chaoGe
}
})
组件系统 插槽
<slot></slot>
在 组件的模板中定义
<div id="app">
<global-component>首页</global-component>
<global-component>免费课程</global-component>
<global-component>轻课</global-component>
<global-component>学位课程</global-component>
<global-component>智能题库</global-component>
</div>
<script>
Vue.component('global-component', {
template: `
<div >
<div class="box"><slot></slot></div>
</div>
`,
});
new Vue({
el: "#app",
})
</script>
具名的slot插槽
用在组件中,有一些特殊的需求
定义组件
let AlertBox = {
template: `<div>
<div class="title"><slot name='title'> Error! </slot></div>
<div class="title"><slot>...</slot></div>
<div class="text"><slot name='text'> 出错了!!</slot></div>
</div>`, // 必须包含在闭合标签那种
}
注册组件
let APP = new Vue({
el: '#app',
compoments: {
"alert-box": AlertBox,
}
})
使用组件
<div id="app">
<alert-box>
<template slot="title">报错: 只在定义的 name='title' 的插槽中显示 </tempalte>
<span slot='text'>覆盖之前插槽中的内容</span>
</alert-box>
<alert-box>没有指定插销的内容 统一在 原始slot 插槽中 显示</alert-box>
<alert-box/>
</div>
------------------------------
计算合 reduce
- python 中
from functools import reduce
data = [
{'num': 10, 'name': '苹果'},
{'num': 3, 'name': '香蕉'},
{'num': 1, 'name': '草莓'},
{'num': 12, 'name': '橙子'},
]
# 求data中所有水果总数 0 是X 的默认值
ret3 = reduce(lambda x, y: x+y['num'], data, 0)
print(ret3)
- js中
<script>
let data = [
{'num': 10, 'name': '苹果'},
{'num': 3, 'name': '香蕉'},
{'num': 1, 'name': '草莓'},
{'num': 12, 'name': '橙子'},
];
/*
let ret = data.reduce(function (x,y) {
return x+y.num
}, 0);
*/
let ret = data.reduce((x,y) =>{
return x+y.num
}, 0);
console.log(ret)
</script>
vue的 生命周期 钩子函数
-
8个钩子函数 (Hook)
-
常用 :
created: 多用来ajax从后端获取数据
mounted: 文档已经渲染完毕,绑定事件!
let app = new Vue({
el: '#app',
data: {
name: 'Alex'
},
// template: `<div class="s16">嘿嘿嘿</div>`,
beforeCreate(){
// 在创建实例之前,data只声明但没有赋值
console.log(this.name);
console.log('------ beforeCreate -------');
},
created(){
// 创建实例之后
console.log(this.name);
console.log('------ created -------');
},
// 挂载
beforeMount(){
// 在挂载DOM之前
console.log(document.getElementById('app'));
console.log('------ beforeMount -------');
},
mounted(){
// 挂载DOM
console.log(document.getElementById('app'));
console.log('------ mounted -------');
},
// 更新操作
beforeUpdate(){
console.log('准备要更新,但是还没有更新');
console.log('------ beforeUpdate -------');
},
updated(){
console.log('更新完成了');
console.log('------ updated -------');
},
})
调用父组件的原生事件
<!-- 调用父组件的原生事件 native 原生的 -->
<button v-on:click.native="show"></button>
Vue组件的通信
父组件 -> 子组件
在子组件中 通过 props声明 需要被传递的数据
在父组件中 通过 v-bind:name="值"
传递数据
子组件 -> 父组件
在子组件通过 $emit(自定义事件)
向外抛出事件
在父组件通过 v-on:自定义事件
触发执行自己的事件
子组件1-> 子组件2
在组件1中 通过公用的 Vue对象 bus
抛出自定义事件 bus.$emit('自定义事件', 数据)
在子组件2中的 mounted
方法中 给 bus 绑定监听事件 bus.$on('自定义事件', (val)=>{...})
\