MVVM模式
- Model: 负责数据存储
- View: 负责页面展示
- View Model:负责业务逻辑处理(比如Ajax请求等) , 对数据进行加工后交给视图展示
MVC模式(设计模式,前后端都有模式存在)
M->mdel->模型->数据(js变量)
V>view- >视图>用户所见界面(HTML,CSS)
C-control->控制器->$州交工>如如根据视也与H必山6收交故(i对DOM对象绑定事们,将交易进行修改
提高开发效率的发展历程:
原生|S. > Jquery之类的类库-> 前端模板引|擎-> Vuejs/Angularjs/Reactjs (能够帮助我们减少不必要的DOM操作(虚拟DOM);提高渲染效率;双向数据绑定的概念)
- 在Vue中,一个核心的概念就是:数据驱动,减免手动操作DOM元素。这样的话,可以让前端程序员可以更多的时间去关注数据的业务逻辑。而不是关心DOM是如何渲染。
框架和库的区别
框架:
框架是一套完整的解决方案。
对项目的入侵性较大,项目如果需要更换框架,则需要重新架构整个项目。但是优点也很明显:功能完善、提供了整套的解决方案。
库(插件) :
只是提供某一个小功能,
对项目的侵入性较小,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求。
前端的各种框架
Vue和React的相同点
- 利用虚拟DOM实现快速渲染
- 轻量级
- 响应式组件
- 支持服务器端渲染
- 易于集成路由工具、打包工具以及状态管理工具.
Vue的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="./vue-2.6.11/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{message}}//用{{}}表明此处使用vue
</div>
//script需放在div后面
<script type="text/javascript">
var app=new Vue({
el:"#app",
data:{
message:"Hello world!"
}
})
</script>
</body>
</html>
<!--通过改变message,可以不进行后台交互改变message的值,但若给定指令v-once,也能执行一次性地插值,当数据改变时,插值处的内容不会更新。-->
声明式渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="./vue-2.6.11/dist/vue.js"></script>
</head>
<body>
<div id="app-2">
<span v-bind:title="message">
<!-- v-bind attribute 被称为指令。
指令带有前缀 v-,以表示它们是 Vue 提供的特殊 attribute。
它们会在渲染的 DOM 上应用特殊的响应式行为。
将这个元素节点的 title attribute 和 Vue 实例的 message property 保持一致。 -->
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
<script type="text/javascript">
var app2 = new Vue({
el: '#app-2',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})
</script>
</body>
</html>
控制是否显示
<div id="app-3">
<p v-if="seen">show</p>
</div>
<script type="text/javascript">
var app3=new Vue({
el:'#app-3',
data:{
seen:true
}
})
</script>
<!-- 通过改变app3.seen=false,改变是否显示状态-->
v-for 指令可以绑定数组的数据来渲染一个项目列表
<div id="app-4">
<ol>
<li v-for="todo in todos">
{{todo.text}}
</li>
</ol>
</div>
<script type="text/javascript">
var app4=new Vue({
el:'#app-4',
data:{
todos:[
{text:'学习'},
{text:'运动'},
{text:'阅读'}
]
}
})
</script>
<!-- 通过app4.todos.push({text:'新项目'})增加新项目-->
v-on 处理用户输入
<div id="app-5">
<p>{{message}}</p>
<button v-on:click="reverseMessage">反转消息</button>
</div>
<script type="text/javascript">
var app5=new Vue({
el:'#app-5',
data:{
message:"Hello Vue!"
},methods:{
reverseMessage:function(){
this.message=this.message.split('').reverse().join('')
}
}
})
</script>
<!-- v-on 指令添加一个事件监听器-->
v-model表单-应用双向绑定
<div id="app-6">
<p>{{message}}</p>
<input v-model="message">
</div>
<script type="text/javascript">
var app6=new Vue({
el:'#app-6',
data:{
message:"Hello Vue!"
}
})
</script>
<!-- v-model实现表单输入和应用状态之间的双向绑定-->
组件
Vue.js引入的组件,让分解单一HTML到独立组件成为可能。组件可以自定义元素形式使用,或者使用原生元素但是以is特性做扩展。
全局组件
<ol>
<todo-item></todo-item>
</ol>
<script type="text/javascript">
// 创建组件
Vue.component('todo-item',{
template:'<li>这是一个代办项目</li>'
})
//实例化组件
var app=new Vue({
el:'todo-item'
})
</script>
局部组件
<div id="app"><tag></tag></div>
<script type="text/javascript">
// 创建组件
var tag={template:'<div>这是一个组件</div>'}
//实例化组件
var app=new Vue({
el:'#app',
components:{tag}
})
</script>
v-cloak
当网络较慢,网页还在加载 Vue.js ,而导致 Vue 来不及渲染,这时页面就会显示出 Vue 源代码。我们可以使用 v-cloak 指令来解决这一问题。
<div id="app" v-cloak>
{{context}}
</div>
[v-cloak]{
display: none;
}
在简单项目中,使用 v-cloak 指令是解决屏幕闪动的好方法。但在大型、工程化的项目中(webpack、vue-router)只有一个空的 div 元素,元素中的内容是通过路由挂载来实现的,这时我们就不需要用到 v-cloak 指令咯。
可以用async await简化promise
this.$refs.loginFormRef.validate(async valid => {
if (!valid) {
this.$refs.loginFormRef.resetFields()
} else {
const { status } = await this.$http.post('login', this.loginForm)
console.log(status)
}
v-bind
注意点:
如果需要通过v-bind给class绑定类名,那么不能直接赋值。
默认情况下v-bind会去Model中查找数据,但是Model中没有对应的类名,所以无效,所以不能直接赋值。
如果想让v- bind去style中查找类名,那么就必须把类名放到数组中并且将类名用“”括起来。
<button v-bind:[key]="value"></button>
<div :class="[‘size’,’color’,’active’]"></div>
v-on
注意点:
1.如果是通过v-on来绑定监听事件,那么在指定事件名称的时候不需要写on
2.如果是通过v-on来绑定监听事件,那么在赋值的时候必须赋值一个回调函数的名称
修饰符:
.stop - 调用 event.stopPropagation()。
.prevent - 调用 event.preventDefault()。
.capture - 添加事件侦听器时使用 capture 模式。
.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调。
.left - (2.2.0) 只当点击鼠标左键时触发。
.right - (2.2.0) 只当点击鼠标右键时触发。
.middle - (2.2.0) 只当点击鼠标中键时触发。
.passive - (2.3.0) 以 { passive: true } 模式添加侦听器
<!-- 方法处理器 -->
<button v-on:click="doThis"></button>
<!-- 动态事件 (2.6.0+) -->
<button v-on:[event]="doThis"></button>
<!-- 点击回调只会触发一次 -->
<button v-on:click.once="doThis"></button>
<!-- 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 阻止默认行为 -->
<button @click.prevent="doThis"></button>
自定义指令
1.自定义全局指令
在Vue中除了可以使用Vue内置的一些指令以外我们还可以自定义指令
2.自定义全局指令语法
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
3.指令生命周期方法
自定义指令时一定要明确指令的业务逻辑代码更适合在哪个阶段执行
例如:指令业务逻辑代码中没有用到元素事件,那么可以在bind阶段执行
例如:指令业务逻辑代码中用到了元素事件,那么就需要在inserted阶段执行
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
计算属性
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
过滤器
<div id="app">
<p>{{time|dateFormart("yyyy-MM-dd")}}</p>
</div>
<script>
Vue.filter('dateFormart',function(value,fmStr){
let date=new Date(value);
let year=date.getFullYear();
let month=date.getMonth()+'';
let day=date.getDate()+'';
let hour=date.getHours()+'';
let minute=date.getMinutes()+'';
let second=date.getSeconds()+'';
if(fmStr&&fmStr==="yyyy-MM-dd"){
return year+'-'+month.padStart(2,'0')+'-'+day.padStart(2,'0');
}
return year+'-'+month.padStart(2,'0')+'-'+day.padStart(2,'0')+' '+hour.padStart(2,'0')+':'+minute.padStart(2,'0')+':'+second.padStart(2,'0');
})
let vue=new Vue({
el:'#app',
data:{
time:Date.now()
}
});
</script>
学生管理系统-增删改查
<!DOCTYPE html>
<head>
<script src="./vue.js"></script>
<style>
*{
margin: 0;
padding: 0;
}
#app{
width: 800px;
margin: 50px auto;
background: skyblue;
}
table{
width: 100%;
background: #000;
}
table tr{
background: white;
}
form{
width: 100%;
display: flex;
justify-content: space-between;
}
</style>
</head>
<body>
<div id="app">
<form v-show="isShow">
<input type="text" name="" id="" placeholder="请输入序号" v-model="person.id">
<input type="text" name="" id="" placeholder="请输入姓名" v-model="person.name">
<input type="text" name="" id="" placeholder="请输入分数" v-model="person.score">
<input type="submit" name="" id="" value="新增" @click.prevent="add">
<input type="submit" name="" id="" value="查询" @click.prevent="query">
</form>
<table>
<tr>
<th>序号</th>
<th>姓名</th>
<th>分数</th>
<th>时间</th>
<th>操作</th>
</tr>
<tr v-for="(person,index) in persons">
<!-- <td><input type="text" name="" id="" :value="person.id" :disabled="isDisabled"></td>
<td><input type="text" name="" id="" :value="person.name" :disabled="isDisabled"></td>
<td><input type="text" name="" id="" :value="person.score" :disabled="isDisabled"></td>
<td><input type="text" name="" id="" :value="person.time | dateFormart" :disabled="isDisabled"></td> -->
<td><input type="text" name="" id="" v-model="person.id" :disabled="isDisabled"></td>
<td><input type="text" name="" id="" v-model="person.name" :disabled="isDisabled"></td>
<td><input type="text" name="" id="" v-model="person.score" :disabled="isDisabled"></td>
<td><input type="text" name="" id="" :value="person.time | dateFormart" disabled></td>
<td>
<a href="#" @click.prevent="edit">编辑</a>
<a href="#" @click.prevent="del(index)">删除</a>
<a href="#" @click.prevent="toggle">更多操作</a>
</td>
</tr>
</table>
</div>
<script>
Vue.filter('dateFormart',function(value){
let date=new Date(value);
let year=date.getFullYear();
let month=date.getMonth()+'';
let day=date.getDate()+'';
let hour=date.getHours()+'';
let minute=date.getMinutes()+'';
let second=date.getSeconds()+'';
return year+'-'+month.padStart(2,'0')+'-'+day.padStart(2,'0')+' '+hour.padStart(2,'0')+':'+minute.padStart(2,'0')+':'+second.padStart(2,'0');
})
let vue=new Vue({
el:'#app',
data:{
isDisabled:true,
isShow:false,
persons:[{
id:1,
name:'zs',
score:"90",
time:Date.now()
},{
id:2,
name:'ww',
score:"80",
time:Date.now()
},{
id:3,
name:'ls',
score:"70",
time:Date.now()
}],
person:{
id:'',
name:'',
score:''
}
},
methods:{
edit(){
this.isDisabled=!this.isDisabled;
},
toggle(){
this.isShow=!this.isShow;
},
del(index){
this.persons.splice(index,1);
},
add(){
this.person.time=Date.now();
this.persons.push(this.person);
this.person={
id:'',
name:'',
score:''
}
},
query(){
console.log(this.person.score)
let newPersons=this.persons.filter((sigperson)=>{
if(sigperson.score===this.person.score){
return true;
}
});
this.persons=newPersons;
}
}
})
</script>
</body>
过渡动画
1.如何给Vue控制的元素添加过渡动画
1.1将需要执行动画的元素放到transition组件中
1.2当transition组件中的元素显示时会自动查找. v-enter/. v-enter-active/. v-enter-to类名当transition组件中的元素隐藏时会自动查找. v-leave/ . v-leave -active/. v-leave-to类名
1.3我们只需要在.v-enter和.v-leave-to中指定动画动画开始的状态在. v-enter-active和. v-leave -active中指定动画执行的状态即可完成过渡动画
一个transition中只能放一个元素
<!DOCTYPE html>
<head>
<script src="./vue.js"></script>
<style>
*{
margin: 0;
padding: 0;
}
.box1{
width: 200px;
height: 200px;
background-color:red;
}
.change-enter-active, .change-leave-active{
transition: opacity 3s;
}
.change-enter, .change-leave-to{
opacity: 0;
}
</style>
</head>
<body>
<div id="app">
<button @click="toggle">切换</button>
<transition name="change">
<div class="box1" v-show="isShow"></div>
</transition>
</div>
<script>
let vue=new Vue({
el:'#app',
data:{
isShow:false
},
methods:{
toggle(){
this.isShow=!this.isShow;
}
}
})
</script>
</body>
2.初始动画设置
默认情况下第一次进入的时候没没有动画的
如果想一进来就有动画,我们J可以通过给transition添加appear属性的方式告诉Vue第1次进入就要显示动画
<transition name="change" appear>
<div class="box1" v-show="isShow"></div>
</transition>
3.如何给多个不同的元索指定不同的动画
如果有个不同的元素而要执行不同的过渡动画,那么我们可以通过给transition指定name的方式来指定进入之前/进入之后/进入过程中,离开之前/离开之后/离开过程中对应的类名,实现不同的元素执行不同的过被动画
1.当前过渡有在的问题
transition类名的方式确实能够实现过渡效果,但是实现的过渡效果并不能保存动画之后的状态。因为Vue内部的实现是在过程中动态绑定类名,过程完成之后删除类名正式因为删除了类名,所以不能保存最终的效果
2.在Vue中如何保存过渡最终的效果
通过Vue提供的JS钩子米实现过渡动画
v on:before enter=”beforeEinter” 进入动画之前
v-on:enter”enter"进入动画执行过程中
v on:after enter=”afterEnter” 进入动画完成之后
v-on:enter-cancelled=" enterCancelled”进入动画被取消
v-on: before -leave=" beforeLeave" 离开动画之前
v-on:leave="leave"离 开动画执行过程中
V -on:after- leave=' afterLeave” 离开动画完成之后
v-on: leave-cancel led=" leaveCancelled"离开动画被取消
3. JS钩子实现过渡注意点
3.1在动画过程中必须写上el. offsetWidth或书e1. offsetHeight
3.2在enter和leave方法中必须调用done方法,否则after-enter和alter- leave不会执行
3.3需要需要添加初始动用,那么需要把done方法包裹到setTimeout方法中调用
<!DOCTYPE html>
<head>
<script src="./vue.js"></script>
<style>
*{
margin: 0;
padding: 0;
}
.box1{
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div id="app">
<button @click="toggle">切换</button>
<!-- 避免vue查找类名,通过添加 v-bind:css="false" 避免 -->
<transition v-bind:css="false"
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
name="change" appear>
<div class="box1" v-show="isShow"></div>
</transition>
</div>
<script>
let vue=new Vue({
el:'#app',
data:{
isShow:true
},
methods:{
toggle(){
this.isShow=!this.isShow;
},
beforeEnter(el){
el.style.opacity="0";
},
enter(el,done){
// 如果通过js钩子实现过渡动画,必须在动画执行过程中的回调函数中写上
// el.offsetWidth/el.offsetHeight
el.offsetWidth;
el.style.transition="all 3s";
// done();若想一进来就出现动画效果需要采用setTimeout
setTimeout(function(){
done();
},0);
},
afterEnter(el){
el.style.opacity="1";
el.style.marginLeft="500px";
}
}
})
</script>
</body>
velocity动画
Velocity(el,{opacity:1,marginLeft:"500px"},3000);
v-for注意点
1.v-for为了提升性能,在更新已渲染过的元素列表时,会采用“就地复用”策略。也正是因为这个策略,在某些时刻会导致我们的数据混乱。
例如:在列表前面新增了内容
- 1.2为了解决这个问题,我们可以在渲染列表的时候给每一个元素加上一个独无二的key
v-for在更新已经渲染过的元素列表时,会先判断key是否相同,如果相同则复用,如果不同则重新创建
- key属性注意点
不能使用index的作为key,因为当列表的内容新增或者删除时index都会发生变化这就导致了不能很好的复用没有发生改变的元素,大大降低了渲染的效率
<ul>
<transition-group appear tag="ul">
<li v-for="(person,index) in persons" :key="person.id" @click="del(index)">
<input type="checkbox">
<span>{{index}}-{{person.name}}</span>
</li>
</transition-group>
</ul>
Vue两大核心: 1. 数据驱动界面改变2. 组件化
1.什么是组件?什么是组件化?
1.1在前端开发中组件就是把个很大的界面拆分为多个小的界面,每一个小的界面就是个组件
1.2将大界面拆分成小界面就是组件化
2.组件化的好处
2.1可以简化Vue实例的代码
2.2可以提高复用性
3. Vue中如何创建组件?
3.1 创建组件构造器
3.2 注册已经创建好的组件
3.3 使用注册好的组件
自定义组件中的data和methods
Vue实例控制的区域和当于一个大的组件,在大组件中我们可以使用data和methods而我们自定义的组件也是一个组件,所以在自定义的组件中也能使用data和methods
2.自定义组件中data注意点
在自定义组件中不能像在vue实例中一样直接使用data而是必须通过返回函数的方式来使用data
data:function(){
return {msg:"返回数据"}
}
组件中的data如果不是通过函数返回的,那么多个组件就会公用一份数据,就会导致数据混乱如果组件中的data是通过函数返回的,那么每创建个新的组件,都会调用一次这个方法,将这个方法返回的数据和当前创建的组件绑定在起,这样就有效的避免了数据混乱
<!DOCTYPE html>
<head>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<abc></abc>
<abc></abc>
<abc></abc>
</div>
<template id="info">
<div>
<button @click="add">累加</button>
<p>{{number}}</p>
</div>
</template>
<script>
Vue.component("abc",{
template:"#info",
data:function(){return{number:0}},
methods:{
add(){
this.number++;
}
}
})
let vue=new Vue({
el:"#app"
})
</script>
</body>
组件切换
<!DOCTYPE html>
<head>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<button @click="toggle">切换</button>
<keep-alive>
<component v-bind:is="name"></component>
</keep-alive>
</div>
<template id="isshow">
<div>
<p>我是显示</p>
<input type="checkbox">
</div>
</template>
<template id="notshow">
<div>
<p>我是不显示</p>
</div>
</template>
<script>
Vue.component("ishow",{
template:"#isshow",
});
Vue.component("nshow",{
template:"#notshow",
});
let vue=new Vue({
el:"#app",
data:{
isShow:false,
name:'ishow'
},
methods:{
toggle(){
this.isShow=!this.isShow;
this.name=this.name==="ishow"?"nshow":"ishow"
}
}
})
</script>
</body>
1.如何给组件添加动画?
给组件添加动画和过去给元素添加动画样如果是单个组件就使用transition。如果是多个组件就使用transition-group
2.过渡动画注意点
默认情况下进入动画和离开动画是同时执行的,如果想”一个做完之后再做另一个,需要指定动画模式
同时生效的进入和离开的过渡不能满足所有要求,所以 Vue 提供了过渡模式
in-out:
新元素先进行过渡,完成之后当前元素过渡离开。
out-in:
当前元素先进行过渡,完成之后新元素过渡进入。
<transition mode="in-out">
<component v-bind:is="name"></component>
</transition>
什么是父子组件?
在一个组件中又定义了其它组件就是父子组件
其实局部组件就是最简单的父子组件,因为我们说过可以把Vue实例看做是一个大组件
我们在Vue实例中定义了局部组件,就相当于在大组件里面定义了小组件,所以实局部组件就是最简单的父子组件
如何定义其它的父子组件
自定义组件中可以使用data,可以使用methods.当然自定义组件中也可以使用components所以我们也可以在自定义组件中再定义其它组件
<!DOCTYPE html>
<head>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<home></home>
</div>
<template id="info">
<div>
<p>我是首页</p>
</div>
</template>
<script>
let vue=new Vue({
el:"#app",
components:{
"home":{
template:"#info"
}
}
})
</script>
</body>
<!DOCTYPE html>
<head>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<father></father>
</div> <template id="father">
<div>
<p>我是父组件</p>
<son></son>
</div>
</template>
<template id="son">
<div>
<p>我是子组件</p>
</div>
</template>
<script>
Vue.component("father",{
template:"#father",
components:{
"son":{
template:"#son"
}
}
});
let vue=new Vue({
el:"#app",
})
</script>
</body>
局部组件-父子组件
let vue=new Vue({
el:"#app",
components:{
"father":{
template:"#father",
components:{
"son":{
template:"#son",
}
}
}
}
})
1.父子组件传递?
在Vue中子组件是不能访问父组件的数据的,如果子组件想要访问父组件的数据,必须通过父组件传递
2.如何传递
2.1在父组件中通过v-bind传递数据
传递格式v-bind:自定义接收名称=”要 传递数据”
2.2在子组件中通过props接收数据,接收格式props: [” 自定义接收名称”]
<body>
<div id="app">
<father></father>
</div> <template id="father">
<div>
<p>{{name}}</p>
<p>{{age}}</p>
<!--数值传递-->
<son :parentname="name"></son>
</div>
</template>
<template id="son">
<div>
<p>子组件</p>
<p>{{parentname}}</p>
</div>
</template>
<script>
Vue.component("father",{
template:"#father",
data:function(){
return {
name:"zss",
age:"18",
}
},
components:{
"son":{
template:"#son",
//数值接收
props:["parentname"]
}
}
});
let vue=new Vue({
el:"#app",
})
</script>
</body>
1.父子组件方法传递?
在Vue中子组件中不能访问父组件的方法的,如果子组件想要访问父组件的方法,必须通过父组件传递
2.如何传递方法
- 在父组件中通过v-on传递方法,传递格式v-on:自定义接收名称=要传递方法”
- 在子组件中自定义一个方法
- 在自定义方法中通过this.$emit('自定义接收名称’) ;触发传递过来的方法
<template id="father">
<div>
<button @click="say">按钮</button>
<son @parentsay="say" :parentname="name"></son>
</div>
</template>
<template id="son">
<div>
<p>子组件</p>
<button @click="sonFn">按钮</button>
<p>{{parentname}}</p>
</div>
</template>
<script>
Vue.component("father",{
template:"#father",
data:function(){
return {
name:"zss",
age:"18",
}
},
methods:{
say(){
alert("hello")
}
},
components:{
"son":{
template:"#son",
props:["parentname"],
/*
如果传递方法,在子组件需要在子组件自定义中通过
this.$emit("自定义接受名称")来激活父组件传递的方法
*/
methods:{
sonFn(){
this.$emit("parentsay");
},
}
}
}
});
</script>
1.如何将子组件数据传递给父组件
既然我们可以将父组件的方法传递给子组件既然我们可以在子组件中调用父组件中的方法,
那么我们就可以在调用方法的时候给方法传递参数传递的参数,就是我们需要传递的数据
Vue.component("father",{
template:"#father",
data:function(){
return {
name:"zss",
age:"18",
}
},
methods:{
say(msg){
alert("hello")
console.log(msg)
}
},
components:{
"son":{
template:"#son",
props:["parentname"],
/*
通过第二个参数返回数据
*/
methods:{
sonFn(){
this.$emit("parentsay","www");
},
}
}
}
});
1.组件中的命名注意点
1.1注册组件的时候使用了”驼峰命名”,那么在使用时需要转换成”短横线分隔命名”例如:注册时: myFather ->使 用时: my- father
1.2在传递参数的时候如果想使用”驼峰名称”,那么就必须写短横线分隔命名”例如:传递时: parent-name=" name" -> 接 收时:props:[”p! parent.Name"]1.3在传递方法的时候不能使用”驼峰命名”,只能用”短横线分隔命名”
@parent-say=" say" -> this. $emit(" parent-say" ) ;
插槽
<template id="father">
<div>
<!--在使用子组件时,动态添加内容-->
<son>
<!--默认情况下,不能在使用子组件的时候,给子组件动态添加内容
若想添加内容,需使用插槽,son内部写入任何数据都会替换默认内容-->
<div>追加内容</div>
<div slot="one">填充1</div>
<div slot="two">填充2</div>
</son>
</div>
</template>
<template id="son">
<div>
<p>子组件</p>
<!--slot插槽,可以使用默认数据,
没有指定名称,为匿名插槽,多个匿名插槽都会被填充
通过name属性指定插槽名称,具名插槽
默认内容是不会被填充到具名插槽中,通过slot属性指定才行
-->
<slot> 这就是默认值 </slot>
<slot> 这就是默认值 </slot>
<slot name="one"> 这就是默认值 </slot>
<slot name="two"> 这就是默认值 </slot>
</div>
</template>
<template id="father">
<div>
<son>
<!-- 可以用#代替v-slot
v-bind :
v-on @
-->
<template v-slot:one>
<div>填充1</div>
<div>填充1.2</div>
</template>
<template v-slot:two>
<div>填充2</div>
<div>填充2.2</div>
</template>
</son>
</div>
</template>
<template id="son">
<div>
<slot name="one"> 这就是默认值 </slot>
<slot name="two"> 这就是默认值 </slot>
</div>
</template>
<template id="father">
<div>
<son>
<template slot-scope="abc">父组件{{abc.child}}</template>
</son>
</div>
</template>
<template id="son">
<div>
<div>子组件{{child}}</div>
<!--把子组件数据暴露给父组件-->
<slot v-bind:child="child"> 这就是默认值 </slot>
</div>
</template>
<!--匿名插槽-->
<template v-slot:default="abc">父组件{{abc.child}}</template>
<!--具名插槽-->
<template #one="abc">父组件{{abc.child}}</template>
练习:在第一个组件中创建一个input 两个button,实现数据+1,-1
在第二个组件中展示数据
<template id="father">
<div>
<son1 @changsum="change"></son1>
<son2 :parentnum="num"></son2>
</div>
</template>
<template id="son1">
<div>
<input type="text" :value="sum" disabled>
<button @click="add">+1</button>
<button @click="sub">+1</button>
</div>
</template>
<template id="son2">
<p>{{parentnum}}</p>
</template>
<script>
Vue.component("father",{
template:"#father",
data:function(){
return{
num:0,
}
},
methods:{
change(newSum){
this.num=newSum;
}
},
components:{
//第一个子组件
"son1":{
template:"#son1",
data:function(){
return {
sum:0,
}
},
methods:{
add(){
this.sum=this.sum+1;
this.$emit("changsum",this.sum);
},
sub(){
this.sum=this.sum-1;
this.$emit("changsum",this.sum);
},
}
},
//第二个子组件
"son2":{
template:"#son2",
props:["parentnum"]
}
}
});
</script>
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
Vuex解决数据传递问题
<template id="grandfather">
<div>grandfather
<p>{{this.$store.state.msg}}</p>
<father></father>
</div>
</template>
<template id="father">
<div>father
<p>{{this.$store.state.msg}}</p>
</div>
</template>
<script>
const newstore = new Vuex.Store({
state: {
msg:"ssss"
}
})
Vue.component("grandfather",{
template:"#grandfather",
store:newstore,
components:{
"father":{
template:"#father",
}
}
})
</script>
兄弟共享
const store=new Vuex.Store({
state:{
sum:0
},
//通过mutations操作数据
mutations:{
mAdd(state){
state.sum=state.sum+1;
},
mSub(state){
state.sum=state.sum-1;
}
}
})
Vue.component("father",{
template:"#father",
store:store,
components:{
//第一个子组件
"son1":{
template:"#son1",
methods:{
add(){
// this.$store.state.sum=this.$store.state.sum+1;
this.$store.commit("mAdd");
},
sub(){
// this.$store.state.sum=this.$store.state.sum-1;
this.$store.commit("mSub");
},
}
},
//第二个子组件
"son2":{
template:"#son2"
}
}
});