Vue基础(day04)
程序员文章站
2024-02-15 19:04:17
...
Vue.js(第四天)
复习
小球动画的实现
<head>
<meta charset="utf-8">
<title></title>
<script src="lib/vue.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css">
.ball{
width: 15px;
height: 15px;
background-color: red;
border-radius: 51%;
}
</style>
</head>
<body>
<div id="app">
<input type="button" value="加入购物车" @click="flag = !flag"/>
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter">
<div class="ball" v-if="flag"></div>
</transition>
</div>
<script type="text/javascript">
//创建Vue实例,得到ViewModel
var vm = new Vue({
el:'#app',
data:{
flag:false
},
methods:{
beforeEnter(el){
el.style.transform = 'translate(0,0)'
},
enter(el,done){
el.offsetWidth
el.style.transform = 'translate(150px,450px)'
el.style.transition = 'all 1s ease'
done()
},
afterEnter(el){
// 这句话,第一个功能,是控制小球的显示与隐藏。
// 第二个功能:直接跳过后半场动画,让flag表示符直接变为false
// 当第二次再点击按钮的时候, flag flag -> true
this.flag = !this.flag
// el.style.opacity = 0
// Vue 把一个完整的动画,是哦那个钩子函数,拆分为了两部分:
// 我们使用 flag 标识符,来表示动画的切换;
// 刚以开始,flag = false -> true -> false
}
}
})
</script>
</body>
- 通过before-enter 定义动画的开始部分,设置动画的起始位置。
- 默认必须传入参数el
- 通过enter 定义动画效果以及终点位置、设置过度属性。调用after-enter函数
- 默认必须传入**el **和 **done **两个参数。
- el.offsetWidth 用来实现 过度的动画,没有它就没有动画实现的效果。
- transform 用来实现动画最终的位置(translate(150px,450px))。
- transition 用来设置动画持续的时间,并且全部应用在动画效果中。
- done() 用来实现调用after-enter 函数,这个函数主要是将小球隐藏(因为在button中已经将其显示出来,所以直接将其隐藏,方便下一次动画的触发)。
- 通过after-enter
- 直接将动画的物体直接隐藏。
组件的定义方式
<body>
<div id="app">
<!-- <mylogin1></mylogin1> -->
<login></login>
</div>
<script type="text/javascript">
//定义组件的时候,如果要定义全局组件,Vue.component('组件的名称',组件的模板对象)
//组件模板对象{}
//通过 对象 自变量的形式,定义了组件模块对象。
var login = {
template: '<h1>1234</h1>'
}
// 通过 Vue.component 把组件模板对象,注册为一个全局的Vue组件,同时,为这个组件起了一个名字,可以让我们通过标签的形式,在页面中引入这个组件。
Vue.component('mylogin1',login)
//创建Vue实例,得到ViewModel
var vm = new Vue({
el:'#app',
data:{
},
methods:{
},
components:{
// '组件的名称':{组件模板对象}
// 'mylogin':login
login//属性和方法的简写
}
})
</script>
</body>
全局组件
定义在非Vue实例下,通过Vue.component定义全局组件。
- 在定义的时候可以直接使用引用变量的方法定义
- var login = { template: ‘
1234
’} - Vue.component(‘mylogin’,login)
- var login = { template: ‘
- 也可以直接定义
局部组件
在Vue实例中的components中直接定义即可:
components:{
// ‘组件的名称’:{组件模板对象}
// ‘mylogin’:login
login//属性和方法的简写
}
组件
父组件向子组件传值
<body>
<div id="app">
<!-- 父组件,我们可以在引用子组件的时候,通过属性绑定(v-bind:)的形式,把需要给传递给父组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用 -->
<com1 v-bind:parentmsg= "msg"></com1>
</div>
<script type="text/javascript">
//创建Vue实例,得到ViewModel
var vm = new Vue({
el:'#app',
data:{
msg: '123 啊-父组件中的数据'
},
methods:{
},
components:{//定义局部组件,无法调用Vm实例中的data 和 methods ,其内部可以使用自己的数据和方法
//结论:经过演示,子组件中,默认无法访问到父组件中的data数据和methods中的方法
com1: {
data(){//子组件中的data数据,并不是通过父组件传递过来的,而是子组件自身私有的,比如:子组件通过Ajax,请求回来的数据,都可以放到data身上
//data中的数据,都是可读可写的;
return {
title:'123',
content:'qqq'
}
},// 组件中的data 是一种方法,一定要注意
template:'<h1 @click="change">这是子组件 --- {{parentmsg}}</h1>',
// 组件中的所有 props 中的数据,都是通过父组件传递给子组件的。
props:['parentmsg'],
//props中的数据都是只读的,无法重新赋值(强制会报错!)
//把父组件传递过来的parentmsg 属性,现在props数组中定义以下,这样,就可以解决这个问题
directives:{},
components:{},
methods:{
change(){
this.parentmsg = '你被修改了'
alert("ping")
}
}
}
}
})
</script>
</body>
- 实际使用的时候步骤还是蛮长的,但主要分为5点:
-
- 首先是在Vue实例中定义data 数据
-
- 再定义子组件
-
- 通过属性绑定机制v-bind将Vue实例中的数据引用过来。
-
- 在子组件中使用props将数据保存下来。
- props:[‘parentmsg’],
- 这个数据只可读,不能强制赋值。
-
- 通过template:’<h1 @click=“change”>这是子组件 — {{parentmsg}}’,将我们拿到的数据展示出去。
-
父组件向子组件传递方法
<body>
<div id="app">
<!-- 父组件向子组件传递方法 ,使用的是事件绑定机制;v-on(v-on 简写为@),当我们自定义了一个事件属性之后,那么子组件就能够通过某种方式,来调用传递进去的这个方法了 -->
<com2 @func = 'show'></com2>
<!-- 这儿向外展示这个com2组件,同时它也是私有组件,也就是说在id='app'的这个范围内才能使用 -->
</div>
<template id="temp1">
<!-- 这儿定义了HTML结构,定义了之后方便com2来调用 -->
<!-- 这个HTML结构只能是一块,也就是说你里面的内容不管有多少,但是在使用的使用后必须成为一个集体(可以使用div包起来) -->
<div>
<h1>这是 子组件</h1>
<input type="button" value="这是子组件中的按钮,点击它,触发父组件传递过来的func 方法" @click="myclick" />
</div>
</template>
<script type="text/javascript">
//定义了一个自变量类型的组件模板对象
//这儿定义了一个组件模板
var com2 = {
template: '#temp1',//通过指定了一个 ID ,表示说,要取加载 这个指定的ID 的template元素中的内,当作组件的HTML结构
// 这儿使用temp1 使用外部定义的HTML结构
data(){
return {
sonmsg : {
name:'小偷儿子',
age: 6
},
// 这儿定义了结构体中的数据data
}
},
methods:{
myclick(){
// 当点击子组建的而按钮的时候,如何拿到父组件传递过来的func方法,并调用这个方法
//emit 英文原意:是触发、调用、发射的意思
// this.$emit('func',1232,456)
this.$emit('func',this.sonmsg)
}
}
}
//创建Vue实例,得到ViewModel
var vm = new Vue({
el:'#app',
data:{
datamsgFromSon :null
},
methods:{
show(data){
// console.log('调用了父组身上的show方法----'+ data )
this.datamsgFromSon = data
}
},
components:{
// com2 或者可以使用com2:com2
// 私有组件,并且调用com2来使用其定义的组件。
com2 : com2
}
})
</script>
</body>
- 通过是将绑定机制v-on,将Vue实例中的方法绑定到一个自定义的名称中。
- <com2 @func = ‘show’>
- 然后通过子组件中的方法触发传递来的方法。
- this.$emit(‘func’,this.sonmsg)
- 传递方法就跟传递值类似。都得通过子组件中的东西来触发。
组件案例
<body>
<div id="app">
<cmt-box @func = "loadComments"></cmt-box>
<ul class="list-group">
<li class="list-group-item" v-for="item in list" :key = 'item.id'>
<span class="badge">评论人:{{item.user}}</span>
{{ item.content }}
</li>
</ul>
</div>
<template id="tmp1">
<div>
<div class="form-group">
<label >评论人:</label>
<input type="text" class="form-control" v-model="user"/>
</div>
<div class="form-group">
<label >评论内容:</label>
<textarea class="form-control" v-model="content"></textarea>
</div>
<div class="form-group">
<input type="button" value="发表评论" class="btn btn-primary" @click="postComment"/>
</div>
</div>
</template>
<script type="text/javascript">
var commentBox = {
data(){
return{
user:'',
content:'',
}
},
template: '#tmp1',
methods:{
postComment(){
//分析:发表评论的业务逻辑
/**
* 1. 数据存到哪里!存放到localStorage 中 localStorage.setItem('cmts','')
* 2. 先组织处一个最新的评论数据对象
* 3. 想办法把第二部中的得到的评论对象,保存到localStorage中
* 3.1 localStorage 只支持存放字符串数据,要先调用JSON.stringify
* 3.2 在保存最新的评论数据之前,要先从localStorage获取到之前的评论数据(string),转换为一个数组对象,然后把最新的评论push 到这个数组
* 3.3 如果获取到的 localStorage 中的评论字符串,为空不存在,则可以返回一个 '[]' 让JSON.parse去转换
* 3.4 把最新的列表数组,再次调用JSON.stringify 转为字符串,然后调用localStorage.setItem()*/
var comment = {id:Date.now(),user:this.user,content:this.content}
//从localStorage中获取所有的评论
var list = JSON.parse(localStorage.getItem('cmts') || '[]')
list.push(comment)
//保存最新的评论数据
localStorage.setItem('cmts',JSON.stringify(list))
this.user = this.content = ''
this.$emit('func')
}
}
}
//创建Vue实例,得到ViewModel
var vm = new Vue({
el:'#app',
data:{
list:[
{id:Date.now(),user:'李白',content:'天生我才必有用'},
{id:Date.now(),user:'江小白',content:'劝君更进一杯酒'},
{id:Date.now(),user:'小马',content:'我姓马,风吹草低现牛羊的马'},
]
},
beforeCreate() {
//这里不能调用loadComments 方法,因为在执行这个钩子函数的时候,data 和 methods 都还没有被初始化
},
created() {
this.loadComments()
},
methods:{
loadComments(){
//从本地的localStorage中,加载评论列表
var list = JSON.parse(localStorage.getItem('cmts') || '[]')
this.list = list
}
},
components:{
'cmt-box':commentBox
}
})
</script>
</body>
- 直接利用js来操作缓存来实现数据的交换,具体注释在文中。
ref 获取DOM元素
- 通过Vue中的vm实例获取DOM实例
<body>
<div id="app">
<input type="button" value="获取元素" @click="getElement"/>
<h3 id="myh3" ref="myh3">哈哈哈,今天天气太好了!!!</h3>
<hr>
<login ref = "mylogin"></login>
</div>
<script type="text/javascript">
var login = {
template: '<h1>登陆组件</h1>',
data(){
return{
msg:'son msg'
}
},
methods:{
show(){
console.log('调用了子组件的方法')
}
}
}
//创建Vue实例,得到ViewModel
var vm = new Vue({
el:'#app',
data:{
},
methods:{
getElement(){
// console.log(document.getElementById('myh3').innerHTML)
// ref是英文单词 【reference】 值类型和引用类型 【referenceError】
// console.log(this.$refs.myh3.innerText)
// console.log(this.$refs.mylogin.msg)
this.$refs.mylogin.show()
//直接调用方法
}
},
components:{
login
}
})
</script>
</body>
- 通过Vue提供的方法直接来获取DOM 属性,从而不直接操作DOM元素。
- 通过 this.$refs.ref名称.方法名/元素 操作其里面的方法或者元素。
- 通过ref 也可以直接调用Vue子组件中的方法。
路由 Vue-router
路由的基本使用
通过学习基础的路由知识,了解到路由就是我们之前在前端中使用的那些通过a标签链接的位置或者其他的网页!也就是监听URL的变化。
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="lib/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 1.安装 Vue-router 路由模块 -->
<script src="./lib/vue-router%20v3.1.5.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css">
.router-link-active,
.myactive {;
color: red;
font-weight: 800;
font-size: 40px;
}
.v-enter,
.v-leave-to{
opacity: 0;
transform: translateX(140px);
}
.v-enter-active,
.v-leave-active{
transform: all 0.5s ease;
}
</style>
</head>
<body>
<div id="app">
<!-- <a href="#/login">登录</a> -->
<!-- <a href="#/register">注册</a> -->
<!-- router-link 默认渲染为一个a标签 -->
<router-link to="/login" tag="span">登录</router-link>
<router-link to="/register">注册</router-link>
<!-- 这是vue-router提供的元素,专门用来当作占位符的,将来,路由规则,匹配到组件中,就会展示到这个router-view中去 -->
<!-- 所以:我们可以把router-view认为是一个占位符 -->
<transition mode="out-in">
<router-view></router-view>
</transition>
</div>
<script type="text/javascript">
var login = {
template:'<h1>登陆组件</h1>'
}
var register = {
template:'<h1>注册组件</h1>'
}
// 2.创建一个路由对象,当导入vue-router包之后,在window全局对象中,就有了一个路由的构造函数 ,叫做VueRouter
// 在new 路由对象的时候,可以为构造函数,传递一个配置对象
var rouedrObj = new VueRouter({
// route //在配置对象中route表示【路由配置规则】 的意思
routes:[// 路由匹配规则
// 每个路由规则,都是一个对象,这个规则对象身上,有两个必须的属性;
// 属性1 是path,表示监听 哪个路由的链接地址;
// 属性2 是component ,表示如果 路由是前面匹配到的path,则展示component 属性对印的那个组件
// 注意:component 的属性值,必须是一个组件模板对象,不能是组件的引用名称
// {path:'/',component:login},
{path:'',redirect:'/login'},// 这里的 redirect 和 node 中的redirect 完全是两码事,在vue中会强制下载页面
{path:'/login',component:login},
{path:'/register',component:register}
],
linkActiveClass:'myactive'
})
//创建Vue实例,得到ViewModel
var vm = new Vue({
el:'#app',
data:{
},
methods:{
},
router:rouedrObj,
// 将路由规则对象,注册到vm实例上,用来监听url地址的变化,然后展示对应的组件
})
</script>
</body>
</html>
- 首先安装 Vue-router 路由模块。
- 在script中配置路由,也就是var rouedrObj = new VueRouter({ }).
- routes 路由的匹配规则。
- 通过router-link 来绑定页面的触发。
- 设置特定页面的占位。
- 用来提供过度的动画。
- 在vm实例中注册路由规则对象。(这样才能监url的变化)。
路由中定义参数
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="lib/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/vue-router%20v3.1.5.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<router-link to="/login/12/ls">登录</router-link>
<router-link to="/register">注册</router-link>
<router-view></router-view>
</div>
<script type="text/javascript">
var login = {
template:'<h1>登录 --- {{this.$route.params.id}} --- {{$route.params.name}}</h1>',
data(){
return{
msg:'123',
}
},
created(){
console.log(this.$route.query.id)
}
}
var register = {
template:'<h1>注册</h1>'
}
var router = new VueRouter({
routes:[
// {path:'',redirect:'/login'},
{path:'/login/:id/:name',component:login},
{path:'/register',component:register}
]
})
//创建Vue实例,得到ViewModel
var vm = new Vue({
el:'#app',
data:{
},
methods:{
},
router
})
</script>
</body>
</html>
- 在路由中定义参数,还是在组件模板对象中定义,方法的使用还是在组件模板对象中使用。
- 还可以通过route中的属性,来展示相应的数据。
- console.log(this.$route.query.id)
路由的嵌套
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="lib/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<script src="lib/vue-router%20v3.1.5.js" type="text/javascript" charset="utf-8"></script>
<body>
<div id="app">
<router-link to="/account">Account</router-link>
<router-view></router-view>
</div>
<template id = "temp1">
<div>
<h1>这是 Account 组件</h1>
<router-link to="/account/login">登录</router-link>
<router-link to="/account/register">注册</router-link>
<router-view></router-view>
</div>
</template>
<script type="text/javascript">
var account = {
template: '#temp1'
}
var login = {
template: '<h3>登录</h3>'
}
var register = {
template: '<h3>注册</h3>'
}
var router = new VueRouter({
routes:[
{
path:'/account',
component:account,
/* 使用children 属性,实现子路由时,子路由的path前面不要带/,否则永远以根路径开始请求,这样不方便我们用户去理解URL地址 */
children:[
{path:'login',component:login},
{path:'register',component:register}
]
}
]
})
//创建Vue实例,得到ViewModel
var vm = new Vue({
el:'#app',
data:{
},
methods:{
},
router
})
</script>
</body>
</html>
- 在路由配置中,也就是new VueRouter 中。
- 在路由匹配规则中(routes),使用children 实现子路由。
- 在实现子路由的时候,要注意,子路由的path 前面不要带“/”,否则永远会以根路径来时请求。
- 不带“/”,就会在当前路径下面,相对的请求。
路由—实现经典布局
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="lib/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<script src="lib/vue-router%20v3.1.5.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css">
html,body{
margin: 0;
border: 0;
}
.header{
background-color: orange;
height: 80px;
}
h1{
margin: 0;
padding: 0;
font-size: 16px;
}
.container{
display: flex;
height: 600px;
}
.left{
background-color: lightgreen;
flex: 2;
}
.main{
background-color: lightsalmon;
flex: 8;
}
</style>
<body>
<div id="app">
<router-view ></router-view>
<div class="container">
<router-view name="left"></router-view>
<router-view name="main"></router-view>
</div>
</div>
<script type="text/javascript">
var header = {
template:'<h1 class = "header">Header 头部区域</h1>'
}
var leftBox = {
template:'<h1 class = "left">Left 侧边栏区域</h1>'
}
var mainBox = {
template:'<h1 class = "main">mainBox 主体区域</h1>'
}
// 创建路由对象
var router = new VueRouter({
routes:[
// { path:'/',component:header },
// { path:'/left',component:leftBox },
// { path:'/main',component:mainBox },
{ path:'/',components:{
'default':header,
'left':leftBox,
'main':mainBox
} }
]
})
//创建Vue实例,得到ViewModel
var vm = new Vue({
el:'#app',
data:{
},
methods:{
},
router
})
</script>
</body>
</html>
- 在同一个Vm 实例下面实现页面的布局,就要用到路由,这样才可以实现相关属性的绑定,以及数据的传输。
- 首先考虑布局制定相应的样式。
- 再在页面中的相应位置留置。
- 留置的router-view 就会在后面渲染页面。
- 在必要的router-view中使用name指定相应的组件模板对象的路径,
- 创建路由对象。
- 明确组件模板对象对应的路由地址。
所有文件已上传GitHub
上一篇: Switch详解