vue使用
自学vue
1.MVVM模式
MVVM模式包含三个部分
M 模型
V 视图
VM 视图模型
实例化vue类的时候,要传递参数对象
通过el属性与页面中的模板绑定上
通过data属性与模型数据绑定上
//小例子
<body>
<div id="app">
<span>{{ msg }}</span>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
msg:'我和我的女友'
}
})
//视图改变 数据更新 改变之后span标签中会是耿泽世
vm.msg ='耿泽世'
</script>
</body>
2.数据绑定的实现
<body>
<div id="app">
<span>{{ msg_list[0] }}---{{ msg_list[1] }}</span>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
msg_list:['我和我的女友','我和女友相处的日子']
}
})
//修改完值以后打印的还是 我和我的女友---我和女友相处的日子
vm.msg_list[0]='耿泽世'
</script>
</body>
----------------------------------
//解决上面的问题 (新数组替换)
<body>
<div id="app">
<span>{{ msg_list[0] }}---{{ msg_list[1] }}</span>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
msg_list:['我和我的女友','我和女友相处的日子']
}
})
//解决办法 数组替换
vm.msg_list=['耿泽世','我和女友相处的日子']
</script>
</body>
//前段对象
<body>
<div id="app">
//执行结果 小敏 和 18 有数据丢失
<span>{{ names.name }}---{{ names.age }}---{{ names.sex }}</span>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
names:{
name:'小敏',
age:18
}
}
})
vm.names.total = '女'
</script>
</body>
//解决办法
<body>
<div id="app">
<span>{{ names.name }}---{{ names.age }}---{{ names.sex }}</span>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
names:{
name:'小敏',
age:18
}
}
})
vm.names={
name: '小敏',
age:18,
sex:'女'
}
</script>
</body>
$set方法为了解决上面数据丢失的问题
第一个参数表示数据对象
可以是vue实例化对象 也可以是其他对象
第二个参数表示属性名称
第三个参数表示属性值
<body>
<div id="app">
<span>{{ names.name }}---{{ names.age }}---{{ names.sex }}</span><br>
<span>{{ color_list[0] }}----{{ color_list[1] }}</span>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
color_list:['red','blue'],
names:{
name:'小敏',
age:18
}
}
})
vm.$set(vm.color_list,0,'greeb')
vm.$set(vm.names,'age',10)
</script>
</body>
计算属性数据定义在comptued属性中
定义的是方法,获取的时候,会将执行的结果返回(是计算的)
computed与data的用法是一样的 ,添加给vue实例化对象自身,并设置了特性,定义的时候都是一个对象
key 表示数据名称 value 是一个函数
参数和this都指向vue实例化对象,因此通过参数或者this可以获取vue中的其他数据
必须有返回值 就是获取的数据
<body>
<div id="app">
<span>{{ names.name }}---{{ names.age }}---{{ names.sex }}</span><br>
<span>{{ color_list[0] }}----{{ color_list[1] }}</span>
<span>{{ deaMax }}</span>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
color_list:['red','blue'],
names:{
name:'小敏',
age:18
},
msg:'hello'
},
computed:{
deaMax(v,...args){
return v.msg.toUpperCase();
}
}
})
</script>
</body>
属性绑定
属性绑定的语法:v-bind:key="value"
语法糖:语法糖就是对某个操作的简化,来提高我们的开发效率
v-bind指令的语法糖是冒号语法糖
v-bind:key="value" 可以写成:key="value"
#v-bind的使用
<body>
<div id="app">
<span v-bind:title="tit">{{ msg }}</span>
<span v-bind:title="msg.toUpperCase()">{{ msg }}</span>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
color_list:['red','blue'],
names:{
name:'小敏',
age:18
},
msg:'hello',
tit:'这是一个属性标签'
},
})
</script>
</body>
#v-html 可以识别html标签的
<body>
<div id="app">
<span v-html="msg+'hello'"></span>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
msg:'<a href="https://baidu.com">点击我跳转百度</a>'
},
})
</script>
</body>
#v-text 不会识别html标签
#只能渲染元素的全部内容 避免插值符号闪烁问题
<body>
<div id="app">
<span v-text="msg"></span>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
msg:'<a href="https://baidu.com">点击我跳转百度</a>'
},
})
</script>
</body>
#v-once 该指令用来让内容单次渲染 该指令不需要设置属性值
插值过滤器
"""
插值过滤器技术有三个优势
避免模板臃肿的问题
可以复用
可以跨组件使用
"""
#使用过滤器
"""
语法{{data | 过滤器(参数1,参数2)|过滤器2.....}}
"""
#自定义过滤器
"""
vue自定义过滤器的两种方式
第一种:全局定义,全局定义的过滤器可以在任何实例化对象(组件)中使用
通过:Vue.filter(name,fn)
第二种:局部定义:局部定义的过滤器只能在当前实例化对象(组件)中使用
在vue实例化对象(组件)中,通过filters属性定义
filters:{name:fn}
name表示过滤器名称:建议驼峰式命名
fn(data,...args)表示函数过滤器函数:data表示处理的数据,args表示使用过滤器时传递的参数
必须有返回值 就是处理的结果
全局定义过滤器的时候,注意点:
filter方法不能解构
要在vue实例化对象之前使用
"""
#全局定义过滤器
<body>
<div id="app">
<span >{{ msg|upper(100,200) }}</span>
</div>
<script src="vue.js"></script>
<script>
Vue.filter('upper',(str,...args)=>{
console.log(str)
console.log(args)
return str.toUpperCase()
})
let vm = new Vue({
el:'#app',
data:{
msg:'hello world'
},
})
</script>
</body>
#局部定义过滤器
<body>
<div id="app">
<span>{{ addr|upper1(11,23) }}</span>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
msg:'hello world',
addr:"i'm student "
},
filters:{
upper1(str,...args){
alert(str)
alert(args)
return str.toUpperCase()
}
}
})
</script>
</body>
数据双向绑定
#v-model指令
数据双向绑定有两个方向:
数据由模型进入视图:通过数据绑定实现的 为value绑定模型数据
数据由视图进入模型:通过事件监听实现的 监听input事件,更新数据
#v-clock
用来解决插值符号闪烁的问题
只需要两步:
第一步:为容器元素设置v-cloak
第二步:在style标签内,(style标签要定义在容器元素的前面),通过v-cloak属性选择器 设置 display:none样式 将元素隐藏
注意:
style标签要定义在容器元素的前面
v-cloak只能给容器元素内部的元素使用(包括容器元素)
单选框
#单选框:对单选框实现数据双向绑定,也是用v-model指令
"""
一组单选框绑定同一份数据
选框的值通过value属性定义
此时checked属性失效了
一组单选框的默认值就是绑定数据的值
"""
#单选框的数据绑定
<body>
<div id="app" v-cloak>
<p>
<span>喜欢的运动</span>
<label>篮球<input type="radio" value="篮球" v-model="sport"></label>
<label>足球<input type="radio" value="足球" v-model="sport"></label>
<label>羽毛球<input type="radio" value="羽毛球" v-model="sport"></label>
</p>
<h1>{{ sport }}</h1>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
//sport:''
sport:'篮球'
},
})
</script>
</body>
#多选框
type属性为checkbox 也是用v-model
特点:
一组多选框绑定不同的数据,为了访问方面,将其放在一个命名空间下
选框的值默认是布尔值 通过v-bind:true-value以及v-bind:false-value可以自定义其值
checked属性失效了
玉一组多选框的默认值就是绑定数据的值,如果自定义:true-value以及 :false-value就是自定义数据值
<body>
<div id="app" v-cloak>
<p>
<span>喜欢的兴趣爱好</span>
<label>篮球<input type="checkbox" v-bind:true-value="'选中了篮球'" :false-value="msg" v-model="inst.baskball"></label>
<label>足球<input type="checkbox" v-model="inst.football"></label>
<label>羽毛球<input type="checkbox" v-model="inst.yunmao"></label>
</p>
<h1>你选择的兴趣爱好:{{ inst }}</h1>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
inst:{
//设置默认属性值
yunmao:'选中了羽毛球'
},
msg:'没有选中篮球'
},
})
</script>
</body>
数据监听器
key 被监听的数据名称
value 当数据改变的时候 执行的回调函数
第一个参数表示新的值 第二个参数表示旧的值
this指向vue实例
#例子
<body>
<div id="app" v-cloak>
<input type="text" v-model="num1">
<h1>{{ num1 }}</h1>
<h2>{{ total }}</h2>
</div>
<script src="vue.js"></script>
<script>
let timebar;
let vm = new Vue({
el:'#app',
data(){
return {
num1:100,
total:100
}
},
watch:{
//监听num1 的变化 num1改变会执行
num1(val,...args){
clearInterval(timebar)
timebar = setInterval(()=>{
this.total += this.num1>this.total?1:-1;
if (this.total == this.num1) {
clearInterval(timebar)
}
},10)
}
}
})
</script>
</body>
DOM事件
#事件绑定:vue为了绑定dom事件 提供了v-on指令
语法:v-on:click=-"fn()"
v-on指令的语法糖是@
也可以写成 @click="fu()"
fn代表事件回调函数,定义在vue实例的methods属性中
methods中定义的方法跟data中的定义的数据一样,添加实例化对象自身了
methods中定义的方法不仅仅可以在事件中使用,所有可以获取实例化对象的地方,都可以通过实例化对象来使用该方法
事件修饰符之事件
#通用修饰符
语法:
v-on:click.修饰符 = "fn"
stop:实现阻止冒泡的修饰符 prevent:实现阻止默认行为的修饰符
once:表示单次触发的修饰符 self:表示绑定事件的元素与触发事件的元素是同一个元素
这些修饰符还可以混合使用
#例子
<body>
<div id="app" v-cloak>
<div @click="fun_par">
parte
<button @click.stop="fun_son">请点击</button>
</div>
</div>
<script src="vue.js"></script>
<script>
let timebar;
let vm = new Vue({
el:'#app',
data(){
return {
msg:'这是绑定事件'
}
},
methods:{
fun_par(...args){
console.log('你们好啊!!!')
},
fun_son(...args){
console.log('我是儿子方法!!!!')
}
}
})
</script>
</body>
事件修饰符之鼠标
鼠标键修饰符
left:点击鼠标左键 right:点击鼠标右键
middle:点击鼠标中间件
<body>
<div id="app" v-cloak>
<button @click.right="fun_par">点击</button>
<button @click.left="fun_par">点击</button>
<button @click.middle="fun_par">点击</button>
</div>
<script src="vue.js"></script>
<script>
let timebar;
let vm = new Vue({
el:'#app',
data(){
return {
msg:'这是绑定事件'
}
},
methods:{
fun_par(...args){
console.log('你们好啊!!!')
}
}
})
</script>
</body>
辅助键修饰符
ctrl:点击ctrl辅助键 shift:点击shift辅助键
alt:点击alt辅助键 meta:点击windows|command辅助键
<body>
<div id="app" v-cloak>
<button @click.ctrl="fun_par">点击</button>
<button @click.alt="fun_par">点击</button>
<button @click.shift="fun_par">点击</button>
</div>
<script src="vue.js"></script>
<script>
let timebar;
let vm = new Vue({
el:'#app',
data(){
return {
msg:'这是绑定事件'
}
},
methods:{
fun_par(...args){
console.log('你们好啊!!!')
}
}
})
</script>
</body>
键盘事件修饰符(键盘事件:keydown keyup keypress(输入有效键))
有效修饰符:esc tab space enter delete
up down left right 以及所有字母键
<body>
<div id="app" v-cloak>
<input @keypress.a="inputkey">点击</input>
</div>
<script src="vue.js"></script>
<script>
let timebar;
let vm = new Vue({
el:'#app',
data(){
return {
msg:'这是绑定事件'
}
},
methods:{
inputkey(e){
console.log(e.key,e.keyCode)
console.log(e.key,e.keyCodes,1111)
}
}
})
</script>
</body>
类的绑定
在vue中 为元素绑定类有三种方式
方式一
:class="{}"
key 表示一组类的名称(可以包含空格,切割成多个类)】
方式二
:class="[]"
每一个成员代表一组类 (可以包含空格,切割成多个类)
方式三
:class=="str" 类名之间用空格隔开
#三种方式的例子
<style>
.red1{
color: aqua;
background-color: rebeccapurple;
}
.height1{
height: 100px;
width: 200px;
}
.green1{
color: aquamarine;
background-color: red;
}
.font-si{
font-size: 20px;
}
.color2{
color: black;
}
.bac{
background-color: chartreuse;
}
</style>
<body>
<div id="app" v-cloak>
方式一
<h1 :class="{'red1 height1':true}">耿家庄存</h1>
<h1 :class="{'red1 height1':false}">耿家庄存</h1>
方式二
<h2 :class="['green1 font-si']">我们是辛集市</h2>
方式三
<h3 :class="'color2 '+msg">我爱你中国</h3>
</div>
<script src="vue.js"></script>
<script>
let timebar;
let vm = new Vue({
el:'#app',
data(){
return {
msg:'bac'
}
},
})
</script>
</body>
vue基础部分
vue历史介绍
有时间学习 react
前端框架与库的区别
vue起步
<body>
<div id='app'>
<h1>
{{msg}}
</h1>
<h3>
{{2}}
</h3>
<h3>
"hello"
</h3>
<h3>
//插入对象 第三层花括号的左右两边要有空格以示区分
{{ {id:1} }}
</h3>
<h3>
//插入表达式
{{1>2?"真的":"假的"}}
</h3>
<h3>
//翻转字符串 先用空字符分隔 然后翻转 然后拼接
{{text.split('').reverse().join('')}}
</h3>
<h3>
//插入函数
{{getCont()}}
</h3>
</div>
</body>
//去vue官网下载vue
//通过srcipt标签引入下载的vue.js文件
//初始化
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
msg:'hello vue',
text:'hello',
context:'你好',
msg3:'<h3>你好</h3>'
},
//写所有方法
methods:{
getCont(){
//return '你好'
return this.msg +" " +this.context
}
}
})
v-text和v-html
<div id='app'>
<h1>
<h2 v-text="msg4">
</h2>
<h2 v-html="msg3">
</h2>
</h1>
</div>
//{{}}和v-text的作用是一样的,都是插入值 直接渲染 像js innerText
//v-html 既能插入值 又能插入标签 像js innerHtml
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
msg3:'<p>你好</p>',
msg4:'插入标签'
},
//写所有方法
methods:{
}
})
v-if和v-show v-else-if v-else 后边可以跟表达式
<div id='app'>
<div v-if="Math.random()>0.5">
显示
</div>
<div v-else>
隐藏
</div>
<div>
<h2 v-show="show">
正常显示
</h2>
</div>
</div>
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
show:true
},
//写所有方法
methods:{
}
})
v-if和v-show的区别: v-if 为假删除整个元素 v-show为假改变样式
v-bind绑定
<div id='app'>
//方式一
<a v-bind:href="res.url" v-bind:title="res.title" ></a>
//方式二
<a :href="res.url" :title="res.title" >{{res.name}}</a>
//isActive为真会渲染 为假不会渲染
<h3 v-bind:class="{active:isActive}">
v-bind指令
</h3>
<h3 :style='{color:isColor,fontSize:fontSize+"px"}'>
你好啊
</h3>
</div>
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
res:{
name:'百度',
url:"https://baidu.com",
title:'百度一次',
isColor:red,
fontSize:39
},
isActive:true
},
//写所有方法
methods:{
}
})
v-on绑定事件
<style>
.box{
width:200px;
height:200px;
background-color:red
}
.active{
background-color:green;
}
</style>
<div id='app'>
<h3>
{{num}}
</h3>
//方式一
<button v-on:click="num+1">
+1
</button>
//方式二
<button v-on:click="handClick">
+1
</button>
<div class="box" :class={active:isActive}>
</div>
<button @click="changClick">
切换
</button>
</div>
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
num:0,
isActive:false
},
//写所有方法
methods:{
handClick(){
this.num+=1;
},
changClick(){
//方式一
if(this.isActive==true){
this.isActive=false
}else{
this.isActive=true
}
//方式二
this.isActive = !this.isActive
},
}
})
vue指令之事件修饰符
<button @click.stop="changClick"> //阻止事件冒泡
//提交事件不在重载页面 组件form表单的submit提交事件(默认提交)
<form v-on:submit.stop.preven="onSubmit">
</form>
//可以串联
<form v-on:submit.stop.preven="onSubmit">
</form>
.stop
.prevent
.capture
.self
.once
.passive
<input v-on:keyup.enter="方法名">
.enter
.tab
.delete
.esc
.space
.up
.down
.left
.right
为什么在html中监听事件
1.扫一眼html模板便能轻松定位在js代码里对应的方法
2.因为无须在js里动手绑定事件,viewmode代码可以是非常纯粹的逻辑
3.当一个viewmode被销毁时,所有的事件处理器都会自动被删除,无须担心如何清理
v-for列表渲染
<div id="app">
<div>
//方式一
<lu>
<li v-for="item in menus">
<p>
id:{{item.id}}菜名{{item.name}}
</p>
</li>
</lu>
//方式二
<lu>
<li v-for="(item,index) in menus" :key="item.id">
<p>
id:{{item.id}}菜名{{item.name}}
</p>
</li>
</lu>
//遍历对象 方式一
<ol>
<li v-for="value in obj">
{{value}}
</li>
</ol>
//遍历对象 方式二
<ol>
<li v-for="(val,key) in obj" >
{{value}}----{{key}}
</li>
</ol>
//遍历对象 方式三
<ol>
<li v-for="(val,key) in obj" >
{{value}}----{{key}}
</li>
</ol>
</div>
</div>
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
menus:[
{id:1,name:'大腰子'},
{id:2,name:'烤鸡翅'},
{id:3,name:'烤韭菜'},
],
obj:{
title:"你好",
author:'小马哥'
}
},
//写所有方法
methods:{
}
})
v-model双向数据绑定
<div id="app">
<p>
{{msg}}
</p>
<input type="text" v-model="msg">
</div>
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
msg:''
},
//写所有方法
methods:{
}
})
复选框单选
v-model="checked" //获取的值不是 true 就是 false
复选框多选
网址练习里面有很多 单选框 多选框 等等
http://cn.vuejs.org/v2/guide/forms.html#单选按钮
<div id="app">
<label for='a'>黄瓜</label>
<input type='checkbox' id='a' value='黄瓜' v-mode="checkName">
<label for='c'>西红柿</label>
<input type='checkbox' id='c' value='西红柿' v-mode="checkName">
<label for='b'>毛豆</label>
<input type='checkbox' id='b' value='毛豆' v-mode="checkName">
</div>
<span>{{listName}}</span>
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
listName:[]
},
//写所有方法
methods:{
}
})
<label>{{txt}}</label>
<input v-model.lazy='txt'>
.number数值类型 输入的是文本 会转为数值类型
.trim 过滤用户输入的收尾空白字符
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
txt:''
},
//写所有方法
methods:{
}
})
侦听器
<div id="app">
<input type="text" v-model='msg'>
<h3>
{{msg}}
</h3>
<h3>
{{stus[0].name}}
</h3>
<button @click='stus[0].name'>
改变
</button>
</div>
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
msg:'',
stus:[{name:'jack'}]
},
//写所有方法
methods:{
},
watch:{
//msg 是属于data对象的属性名 value:监视后的行为
'msg':function(newV,oldV){
},
//深度监视 object Array
'stus':{
deep:'true', //表示深度监视
handler:functioni(newV,oldV){
console.log(newV[0].name)
},
}
}
})
//基本的数据类型可以使用watch直接监听 复杂数据类型要深度监视
计算属性
<div id="app">
{{reverseMsg}}
<h3>
{{fullName}}
</h3>
</div>
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
msg:'hellow',
firstname:'小马',
lastName:'哥'
},
//写所有方法
methods:{
},
computed:{
//计算属性最大的优点,产生缓存 如果数据没有产生变化直接从缓冲中取
//存放方法 computed默认只有getter方法
reverseMsg:function(){
return this.msg.split('').reverse().join('')
},
fullName:function(){
return this.firstname + this.lastName
},
}
})
过滤器filters
<div id="app">
<h3>
//方式一
{{price | myPrice}}
//方式二
{{price | myPrice('人民币')}}
//全局过滤器
<h3>
{{msg | 过滤器名字}}
</h3>
</h3>
</div>
//过滤器 为数据添油加醋
const vm = new Vue({
el:'#app',
//声明的是数据属性
data(){
price:10,
msg:'过滤器'
},
//写所有方法
methods:{
},
filters:{
//局部过滤器
//方式一
myPrice:function(price){
return '$' + price
},
myPrice:function(price,a){
return a + price
},
}
})
//创建全局过滤器
Vue.filter(过滤器名字,(val,可以有多个参数)=>{
return val.split('').reverse().join('')
})
vue组件开发
局部组件的创建和使用
//入口
<div id='app'>
//第三部使用子组件
<App></App>
</div>
//引入vue.js文件
<script src="vuejs"></script>
<script>
//创建子组件
//使用局部组件的打油诗:创建 挂载 使用
//第一步
const App = {
//还可以写data
data(){
return {
msg:'我是app组件'
}
}
//template是写html的地方
template:
`
<div>
<h3>{{msg}}</h3>
<h2>我是一个APP组件</h2>
<button @click=handleClick>按钮</button>
</div>
` ,
//还可以写methods方法
methods:{
handleClick(){
this.msg='学习局部组件'
},
},
computed:{
}
}
new Vue({
el:"#app",
data(){
return{
}
},
components:{
//第二步
//挂载子组件
App
}
})
</script>
全局组件
//入口
<div id='app'>
//第三部使用子组件 全局组件可以直接使用
<App></App>
</div>
//引入vue.js文件
<script src="vuejs"></script>
<script>
//创建全局组件
//Vue.component('组件名',对象)
Vue.component('Liu',{
template:`
<div>
我是导航组件
</div>
`
})
//创建子组件
//使用局部组件的打油诗:创建 挂载 使用
//第一步
const App = {
//还可以写data
data(){
return {
msg:'我是app组件'
}
}
//template是写html的地方
template:
`
<div>
//使用全局组件
<Liu></Liu>
</div>
` ,
//还可以写methods方法
methods:{
handleClick(){
this.msg='学习局部组件'
},
},
computed:{
}
}
new Vue({
el:"#app",
data(){
return{
}
},
components:{
//第二步
//挂载子组件
App
}
})
</script>
组件通信父传子
//入口
<div id='app'>
//第三部使用子组件 全局组件可以直接使用
<App></App>
</div>
//引入vue.js文件
<script src="vuejs"></script>
<script>
//全局组件
//子组件
Vue.component('Child',{
template:`
<div>
<h2>我是一个子组件</h2>
//父传子 第三部 使用
<h3>{{childData}}</h3>
</div>
`,
//父组件传值给子组件需要定义的东西(下面可以是字符串 数组等) // 父传子 第二步 接收值
props:['childData']
})
//创建子组件
//使用局部组件的打油诗:创建 挂载 使用
//第一步
//父组件
const App = {
//还可以写data
data(){
return {
msg:'我是父组件传进来的值 '
}
}
//template是写html的地方
template:
`
<div>
//父组件向子组件传值的方式
//父传子 第一步 传值
<Child :childData='msg'></Child>
</div>
` ,
components:{
//用于挂载组件
},
}
new Vue({
el:"#app",
data(){
return{
}
},
components:{
//第二步
//挂载子组件
App
}
})
</script>
1.在子组件中声明props接收父组件挂载的属性
2.可以在子组件的template中任意使用
3.在父组件绑定自定义的属性
上面都有例子
组件通信子传父
//入口
<div id='app'>
//第三部使用子组件 全局组件可以直接使用
<App></App>
</div>
//引入vue.js文件
<script src="vuejs"></script>
<script>
//全局组件
//子组件
Vue.component('Child',{
template:`
<div>
//子传父 第一步
<input type="text" @input="handlInput">
</div>
`,
methods:{
handlInput(e){
const val = e.target.value
//子传父 第二步 第一个参数是父组件的
this.$emit('inputhandl',val)
},
}
})
//创建子组件
//使用局部组件的打油诗:创建 挂载 使用
//第一步
//父组件
const App = {
//还可以写data
data(){
return {
msg:'我是父组件传进来的值 ',
newV:''
}
}
//template是写html的地方
template:
`
<div>
<div class="father">
数据{{newV}}
</div>
//第三部 inputhandl 写到子组件中的$emit 的第一个参数
<Child :childData='msg' @inputhandl="input"></Child>
</div>
` ,
methods:{
//第四部
input(newV){
console.log(newV)
this.newV=newV
}
},
components:{
//用于挂载组件
},
}
new Vue({
el:"#app",
data(){
return{
}
},
components:{
//第二步
//挂载子组件
App
}
})
</script>
//子往父传值
1.在父组件中 子组件上绑定自定义事件
2.在子组件中 触发原生的事件 在事件函数通过this.$emit触发自定义的事件
组件通信之平行通信
//入口
<div id='app'>
//第三部使用子组件 全局组件可以直接使用
<App></App>
</div>
//引入vue.js文件
<script src="vuejs"></script>
<script>
//创建公交车
const bus = new Vue()
Vue.component('B',{
template:`
<div>{{count}}</div>
`,
data(){
return{
count:0
}
},
created(){
//$on 绑定事件
this.$on('add',(n)=>{
this.count+=n
})
//$emit 触发事件
},
})
Vue.component('A',{
template:`
<div>
<button @click="hanlderClick">加入购物车</button>
</div>
`,
data(){
return{
}
},
methods:{
hanlderClick(){
this.$emit('add',1)
},
}
})
//父组件
const App = {
//还可以写data
data(){
return {
}
}
//template是写html的地方
template:
`
<div>
<A></A>
<B></B>
</div>
` ,
methods:{
//第四部
input(newV){
console.log(newV)
this.newV=newV
}
},
components:{
//用于挂载组件
},
}
new Vue({
el:"#app",
data(){
return{
}
},
components:{
//第二步
//挂载子组件
App
}
})
</script>
组件通信其他方式
//入口
<div id='app'>
//第三部使用子组件 全局组件可以直接使用
<App></App>
</div>
//引入vue.js文件
<script src="vuejs"></script>
<script>
//provide
//inject
//父组件 provide来提供变量,然后在子组件中通过inject来注入变量,无论组件嵌套多深
//创建公交车
const bus = new Vue()
Vue.component('B',{
template:`
<div>{{count}}</div>
<div>{{msg }}</div>
`,
data(){
return{
count:0
}
},
inject:['msg'],
created(){
//页面创建时需要父组件的数据 这样用this去
console.log(this.msg)
},
})
Vue.component('A',{
template:`
<div>
<B></B>
</div>
`,
data(){
return{
}
},
created(){
//获取父组件this.$parent
console.log(this.$parent.title)
console.log(this.$children)
},
methods:{
hanlderClick(){
this.$emit('add',1)
},
}
})
//父组件
const App = {
//还可以写data
data(){
return {
title:'我是老爹'
}
},
provide(){
return {
msg:'老爹的数据'
}
}
//template是写html的地方
template:
`
<div>
<A></A>
</div>
` ,
methods:{
//第四部
input(newV){
console.log(newV)
this.newV=newV
}
},
components:{
//用于挂载组件
},
}
new Vue({
el:"#app",
data(){
return{
}
},
components:{
//第二步
//挂载子组件
App
}
})
</script>
插槽
//入口
<div id='app'>
//第三部使用子组件 全局组件可以直接使用
<App></App>
</div>
//引入vue.js文件
<script src="vuejs"></script>
<script>
Vue.components('MBtn',{
template:`
<button>
//留槽
<slot></slot>
</button>
`
})
//父组件
const App = {
//还可以写data
data(){
return {
title:'我是老爹'
}
},
//template是写html的地方
template:
`
<div>
<MBtn><a>登录</a></MBtn>
<MBtn>注册</MBtn>
</div>
` ,
methods:{
//第四部
input(newV){
console.log(newV)
this.newV=newV
}
},
components:{
//用于挂载组件
},
}
new Vue({
el:"#app",
data(){
return{
}
},
components:{
//第二步
//挂载子组件
App
}
})
</script>
具名插槽
//入口
<div id='app'>
//第三部使用子组件 全局组件可以直接使用
<App></App>
</div>
//引入vue.js文件
<script src="vuejs"></script>
<script>
Vue.components('MBtn',{
template:`
<button>
//留槽
<slot name="login"></slot>
<slot name="submit"></slot>
<slot name="regist"></slot>
</button>
`
})
//父组件
const App = {
//还可以写data
data(){
return {
title:'我是老爹'
}
},
//template是写html的地方
template:
`
<div>
<MBtn>
<template slot='login'>
<a>登录</a>
</template>
</MBtn>
<MBtn>
<template slot='submit'>
<a>提交</a>
</template>
</MBtn>
<MBtn>
<template slot='regist'>
<a>注册</a>
</template>
</MBtn>
</div>
` ,
methods:{
//第四部
input(newV){
console.log(newV)
this.newV=newV
}
},
components:{
//用于挂载组件
},
}
new Vue({
el:"#app",
data(){
return{
}
},
components:{
//第二步
//挂载子组件
App
}
})
</script>
作用域插槽
//有时间在重新看一遍
vue中的声明周期
//入口
<div id='app'>
//第三部使用子组件 全局组件可以直接使用
<App></App>
</div>
//引入vue.js文件
<script src="vuejs"></script>
<script>
Vue.component('Test',{
data(){
msg:'周润发'
},
template:`
<div>
<h3>{{msg}}</h3>
</div>
`,
//组件创建之前执行的方法
beforeCreate(){
},
//组件创建完成执行
created(){
//做非常重要的事情 发送ajax请求数据向后端
},
//挂载之前触发的方法
beforeMount(){
},
mounted(){
//发送ajax 也可以
//挂载完成触发
},
beforeUpdate(){
//获取更新之前的dom
//更新之前触发
},
updated(){
//获取最新的dom
//更新之后触发
},
beforeDestroy(){
//销毁之前触发
},
destroyed(){
//销毁完成
},
activated(){
//组件被激活了
},
deactivated(){
//组件被停用了
},
//deactivated和activated需要配合keep-alive标签使用,keep-alive和html标签一样使用,但是需要激活或者停用的代码写在keep-alive里面
})
const App={
data(){
return{}
},
components:{},
template:`
<Test></Test>
`
}
new Vue({
el:"#app",
data(){
return{
}
},
components:{
//第二步
//挂载子组件
App
}
})
</script>
异步组件加载
//创建一个js文件
export default {
data(){
return{
msg:'小马哥'
}
},
template:`
<h3>
{{msg}}
</h3>
`
}
//入口
<div id='app'>
//第三部使用子组件 全局组件可以直接使用
<App></App>
</div>
//引入vue.js文件
<script src="vuejs"></script>
<script type="module">
const App={
data(){
return{}
},
components:{},
template:`
<Test></Test>
`,
comonents:{
Test:()=>import('./Test.js')
},
}
new Vue({
el:"#app",
data(){
return{
}
},
components:{
//第二步
//挂载子组件
App,
}
})
</script>
vue中的ref属性
//引入vue.js文件
<script src="vuejs"></script>
<script type="module">
const App={
data(){
return{}
},
components:{},
template:`
<button ref="btn">按钮</button>
<input type="text" ref='input'>
`,
comonents:{
Test:()=>import('./Test.js')
},
mounted(){
//如果给标签添加ref,获取的就是真实的dom节点
//如果给子组件添加ref,获取的是当前子组件对象
//获取button按钮
console.log(this.$refs.btn)
//自动获取焦点
this.$refs.input.focus();
},
}
new Vue({
el:"#app",
data(){
return{
}
},
components:{
//第二步
//挂载子组件
App,
}
})
</script>
nextTick的用法
<div id="app">
<h3>
{{msg}}
</h3>
</div>
//引入vue.js文件
<script>
const vm=new Vue({
el:'#app',
data(){
return{
msg:"小马哥"
}
}
})
vm.msg='新小马哥'
Vue.nextTick(()=>{
console.log(vm.$el.textContent)
})
</script>
minxin偷懒技术
<div id="app">
<h3>
{{msg}}
</h3>
</div>
//引入vue.js文件
<script>
const myMixin = {
data(){
return{
msg:'123'
}
},
created(){
this.sayHello()
},
methods:{
sayHello(){
console.log('你哈')
}
}
}
//minxin来分发Vue组件中的可复用功能
const vm=new Vue({
el:'#app',
data(){
return{
title:"小马哥"
}
},
mixins:[myMinxin]
})
</script>
进阶了
Vue Cli3脚手架
//基本配置
安装nodejs
终端中输入node -v 保证已安装完成
//安装淘宝镜像源
npm install -g cnpm --registry=https://registry.npm.taobao.org
以后的npm可以用cnpm代替
//安装Vue cli3 脚手架
cnpm install -g @vue/cli
//检查其版本是否正确
vue --version
快速的原型开发
//进入一个文件初始化
npm init
//使用vue serve和vue build 命令对单个*.vue文件进行快速原型开发,不过这需要先额外安装一个全局的扩展
npm install -g @vue/cli-service-global
vue serve 的缺点就是它需要安装全局依赖,这使的它在不同机器上的一致性不能得到保证,因此这只适用于快速原型开发
需要的仅仅是一个App.vue文件
<template>
//编写html
<div>
<h2>
hello word 单页面组件
</h2>
</div>
</template>
<script>
//编写js
export default{
}
</script>
<style scoped>
//编写css样式
</style>
创建项目
vue create 项目名字
需要知道的代码
let sum = 0
this.cart.forEache(c =>{
if(c.active ){
sum += c.price*c.count;
}
})
return sum
return this.cart.reduce((sun,c)=>{
if(c.active){
sum += c.price*c.count
}
return sum
}0)
购物车代码
//需要加微信要代码
组件深入
//使用element-ui需要先下载
npm install element-ui安装
//在main.js 中 写入一下代码
//完整导入
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css0';
import App fro './App.vue'
Vue.user(ElementUI)
//按需求导入
第一步
npm install babel-plugin-component -D
第二步
将.babelrc修改为
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
第三部
接下来,如果你只希望引入部分组件,比如 Button 和 Select,那么需要在 main.js 中写入以下内容:
import Vue from 'vue';
import { Button, Select } from 'element-ui';
import App from './App.vue';
Vue.component(Button.name, Button);
Vue.component(Select.name, Select);
/* 或写为
* Vue.use(Button)
* Vue.use(Select)
*/
new Vue({
el: '#app',
render: h => h(App)
});
//方式二安装
在vue-cli中可以使用vue add element 安装
安装之前注意提前提交当前工作内容,脚手架会覆盖若干文件
发现项目发生了变化,打开App.vue ctrl+z 撤回
自定义组件
<div>
<input :type="type" :value="inputVale" @input="handleInput">
</div>
<script>
export default{
props:{
type:{
type:String,
default:'text'
},
value:{
type:String,
default:""
}
},
data(){
return{
inputVale:this.value
}
},
methods:{
handleInput(e){
this.inputVal = e.target.value
//通知父组件值的更新
this.$emit('input',this.inputVal)
}
},
}
</script>
//在另一个文件中使用
先导入
<m-input v-model=ruleForm.name></m-input>
<m-input type='password' v-model="ruleForm.pwd"></m-input>
vue-router
vue-element-admin 有时间自己预习一下
//如果创建vue项目的时候没有安装 vue-router插件 解决办法
//方法一
npm i vue-router -S
在 main.js中配置
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
//方法二
vue add router
vue-router基本使用
//在没有安装vue-router的情况下执行
npm i vue-router -S
会创建一个router文件夹 里面有index.js文件 文件中这样写
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
//导入页面组件
//配置路由
export default new VueRouter({
routes:[
{
path:'/',
component:Home
}
]
})
//在main.js中引入 创建出来的router文件夹
import router from './router'
//挂载router
new Vue({
router,
})
命名路由
//router中的index.js
export default new VueRouter({
routes:[
{
path:'/',
name:'home', //命名路由
component:Home
}
]
})
在template中的使用
比如:
<router-link :to="{name:'home'}">首页</router-link>
动态路由匹配和路由组件使用
export default new VueRouter({
routes:[
{
path:'/user/:id', //动态路由匹配
name:'user', //命名路由
component:Home
}
]
})
在template中的使用
比如:
<router-link :to="{name:'user',params:{id:1}}">首页</router-link>
<router-link :to="{name:'user',params:{id:2}}">首页</router-link>
//获取user路径后的id值
template中获取
{{$route.params.id}}
//在script中任何地方获取
this.$route.params.id
#可以在监听事件中获取user后面的id
watch:{
$route:(to,from)=>{
console.log(to.params.id)
}
}
//关于路由的方法
beforeRouteUpdate(to,from,next){
console.log(to.params.id)
//一定要调用next方法不然路由会形成堵塞
next()
}
路由和路由匹配优先级
//路由匹配优先级 从上往下
export default new VueRouter({
routes:[
{
path:'/user-*', //动态路由匹配
name:'user', //命名路由
component:Home
}
]
})
在template中
<h4>
{{$route.params.pathMatch}} //可以匹配到user-*的部分
</h4>
路由查询参数
export default new VueRouter({
mode:'history', //可以产生干净的地址栏地址
routes:[
{
path:'/page',
name:'page', //命名路由
component:()=>import('@/views/Page')
}
]
})
templeate中 就是这种请求地址 https://www.page/?id=2&title=foo
<router-link :to="{name:'page',query:{id:2,title:'foo'}}">Page</router-link>
//获取问好后面的值
const title = this.$route.query.title
const id = thie.$route.query.id
const {id,title} = this.$route.query
路由的重定向和别名
export default new VueRouter({
mode:'history', //可以产生干净的地址栏地址
routes:[
{
path:'/' //访问/
redirect:'/home' //重定向到home页面 方式一
redirect:{name:'home'} 方式二
}
{
path:'/home', (可以在页面路径使用)
name:'home', //命名路由
component:()=>import('@/views/home'),
alias:'/aaaa' //起别名 (可以在页面路径使用)
}
]
})
路由组件传值
export default new VueRouter({
mode:'history', //可以产生干净的地址栏地址
routes:[
{
path:'/user/:id',
name:'user', //命名路由
component:()=>import('@/views/User'),
props:true //方式一
props:(route)=>({ //方式二
id:route.params.id,
title:route.query.title
})
}
]
})
在user组件中使用
props:['id'] //方式一
props:['id','title']//方式二
template中使用
{{id}} //方式一
{{id}}{{title}} //方式二
这样访问
localhost:80000/user/2?title=foo
编程式导航
this.$router.push(跳转地址)
this.$router.push({
path:'/'
})
this.$router.push({
name:'user',
params:{id:2}
})
this.$router.go() //0 表示刷新 1 表示前进 -1 表示后退
嵌套路由使用
Profile.vue文件
template中写的
<h1>
我是Profile.vue文件
</h1>
Posts.vue文件
template中写的
<h1>
我是Posts.vue文件
</h1>
export default new VueRouter({
mode:'history', //可以产生干净的地址栏地址
routes:[
{
path:'/user/:id',
name:'user', //命名路由
component:()=>import('@/views/User'),
props:true //方式一
props:(route)=>({ //方式二
id:route.params.id,
title:route.query.title
}),
children:[
{
path:'profile',
component:()=>import('@/views/Profile')
},
{
path:'posts',
component:()=>import('@/views/Posts')
}
]
}
]
})
user.vue中写
//子路由的出口
<router-view></router-view>
在别的文件中使用
<router-link to="/user/1/profile">profile</router-link>
<router-link to="/user/1/posts">posts</router-link>
命名视图
export default new VueRouter({
mode:'history', //可以产生干净的地址栏地址
routes:[
{
path:'/home',
name:'home', //命名路由
components:{
default:Home, //默认名字
//main:Main
main:()=>import('@/views/Main'),
tabanner:()=>import('@/views/Tabanner')
....
}
}
]
})
App.vue中的使用
<router-view></router-view> //默认是home页面的出口
<router-view name='main'></router-view>
<router-view name='tabanner'></router-view>
导航守卫
//全局守卫
const router=new VueRouter({.....})
router.beforeEach((to,from,next)=>{
//....
})
需求 用户登录只有才可以查看网站中的各个页面
模拟
创建Notes.vue文件
template中写的
<div>
<h3>
我是Notes文件
</h3>
</div>
创建登录页面Login.vue文件
template
<h2>
登录页面
</h2>
配置路由
export default new VueRouter({
mode:'history', //可以产生干净的地址栏地址
routes:[
{
path:'/notes',
name:'notes',
component:()=>import('@/views/Notes')
},
{
path:'/login',
name:'login',
component:()=>import('@/views/Login')
},
]
})
App.vue文件中写的
<router-link :to='{name:'notes'}'>我的笔记</router-link>
在main.js中写全局守卫
router.beforeEach((to,from,next)=>{
//to 到哪去
// from 从哪来
if(to.path==='/notes'){
//用户访问了我的笔记页面
const user = JSON.parse(localStorage.getItem('user'))
if(user){
//用户登录
next()
}else{
//用户没有登录 跳转登录页面
next('/login')
}
}
next()//必须调用
})
//组件内部的守卫
beforeRouteEnter 取不到this
beforeRouteUpdate
beforeRouteLeave 离开该路由是被调用 可以使用this
上面三个函数 都有三个参数 to from next
路由meta元信息实现权限管理
创建一个Blog.vue文件
template中写的是
<h3>
我是blog
</h3>
export default new VueRouter({
mode:'history', //可以产生干净的地址栏地址
routes:[
{
path:'/blog',
name:'blog',
component:()=>import('@/views/Blog'),
meta:{
//加到黑名单
requireAuth:true
}
},
]
})
<router-link :to='{name:'blog'}'>我的博客</router-link>
在main.js中写全局守卫
router.beforeEach((to,from,next)=>{
if(to.matched.some(record=>record.meta.requireAuth)){
//需要权限
if(!localStorage.getItem('user')){
next({
path:'/login',
query:{
redirect:to.fullPath//完整的路径
}
})
}else{
next();
}
}
next()
})
vuex
vuex是一个专门vue.js应用程序开发的 状态管理模式
vuex管理状态(向共享的状态)
vuex的基本使用
//线程的项目,如果项目中没有vuex的话 可以使用 vue add vuex下载
下载完成之后会在src目录中多一个 store目录
需要 导入
import store from './store'
和router一样 在vue中注册
new Vue({
router,
store,
.....
})
store文件夹中的index.js文件中的内容
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state:{
//当前的状态]
count:0
},
mutations:{
//同步的方法声明 第二步 方法一 和 方法二都需要
increment(state){
//修改状态
state.count++
}
},
actions:{
//异步的方法声明 第一步 方法一
//increment({commit}){
//commit mutations中声明的方法
//commit('increment')
///}
//修改状态的唯一方法就是提交mutation
},
modules:{
}
})
export default store;
在home组件中
<templeate>
{{count}}
<button @click="increment">
</button>
</templeate>
<script>
export default{
computed:{
count(){
return this.$store.state.count
}
},
methods:{
increment(){
//dispathch 触发actions中声明的方法
this.$store.dispatch('increment')//方法一
this.$store.commit('increment')//方法二
},
},
}
</script>
vuex系列辅助函数
//线程的项目,如果项目中没有vuex的话 可以使用 vue add vuex下载
下载完成之后会在src目录中多一个 store目录
需要 导入
import store from './store'
和router一样 在vue中注册
new Vue({
router,
store,
.....
})
store文件夹中的index.js文件中的内容
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state:{
//当前的状态
count:0,
username:'小白'
},
getters:{
evenOrOdd(state){
return state.count % 2 === 0?'偶数':'基数'
}
},
mutations:{
//同步的方法声明 第二步 方法一 和 方法二都需要
increment(state){
//修改状态
state.count++
}
},
actions:{
//异步的方法声明 第一步 方法一
//increment({commit}){
//commit mutations中声明的方法
//commit('increment')
///}
},
modules:{
}
})
export default store;
在home组件中
//重点使用
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
<templeate>
//方式一
{{count}}
{{username}}
//方式二
{{myCount}}
{{user}}
----------------------
{{evenOrOdd}}
</button>
</templeate>
<script>
export default{
computed:{
/*count(){
return this.$store.state.count
},
username(){
return this.$store.state.username
},*/
/*...mapState(['count','username'])*/方法一
...mapState({
myCount:'count',
user:'username'
}),
--------------
evenOrOdd(){
return this.$store.getters.evenOrOdd
},
...mapGetters(['evenOrOdd'])
-----------------
...mapMutations(['increment'])
------------------------------
...mapActions(['increment'])
----------------------------------
注意:如果router文件夹中有多个文件是这样使用
...mapGetters('文件名',['方法名'])
},
methods:{
increment(){
},
},
}
</script>
如何在组件内部提交数据给vuex
//线程的项目,如果项目中没有vuex的话 可以使用 vue add vuex下载
下载完成之后会在src目录中多一个 store目录
需要 导入
import store from './store'
和router一样 在vue中注册
new Vue({
router,
store,
.....
})
store文件夹中的index.js文件中的内容
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state:{
//当前的状态
count:0,
username:'小白'
},
getters:{
evenOrOdd(state){
return state.count % 2 === 0?'偶数':'基数'
}
},
mutations:{
//同步的方法声明 方法一
/*increment(state,amount){
//修改状态
state.count += amount
}*/
//方法二
increment(state,amount){
//修改状态
state.count += amount
}
},
actions:{
increment({commit,state},{amount}){
commit('increment',amount)
}
},
modules:{
}
})
export default store;
在home组件中
//重点使用
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
<templeate>
//方式一
{{count}}
{{username}}
//方式二
{{myCount}}
{{user}}
----------------------
{{evenOrOdd}}
</button>
</templeate>
<script>
export default{
computed:{
},
methods:{
//方法一
increment(){
this.$store.dispathc('increment',{
amount:10
})
},
//方法二
increment(){
this.$store.dispatch({
type:'increment',
amount
})
},
},
}
</script>
store中有多个文件时 多个文件中的数据怎样共享
//在getters中获取
getters:{
方法名(state,getters,rootState){
//打印一下rootState就可以看出来了
//getters可以调用getters中的自定义方法
}
}
在一个模块中 提交另一个模块数据的时候{root:true} 要加这个
如果想提交另一个模块中的方法,那么需要第三个参数{root:true}
commit('还可以写另一个文件的方法',字典形式传参,{root:true})