Vue.js入门知识day4
复习:实现小球动画
1、html布局
<div id="app">
<input type="button" value="加入购物车" @click="flag=!flag">
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
<div class="ball" v-show="flag"></div>
</transition>
</div>
2、css样式
<style>
.ball{
width: 15px;
height: 15px;
background-color: red;
border-radius: 50%;
}
</style>
3、JavaScript代码
<script>
//创建 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 false -> true
this.flag = !this.flag
// el.style.opacity = 0.5
//Vue把一个完整的动画,使用钩子函数,拆分为了两部分;
//我们使用 flag标识符,来表示动画的切换;
//刚一开始,flag= false -> true -> false
}
}
})
</script>
复习:定义组件的方式
var login = {
template:<h1>1234</h1>
}
var vm = new Vue({
el:'#app',
data:{},
methods:{},
components:{
//'组件的名称':组件的模板对象
//'mylogin':login
login
}
})
组件传值:父组件向子组件传值
1、html布局
<div id="app">
<!--父组件可以在引用子组件的时候通过属性绑定(v-bind:)的形式,把需要传递给子组件的数据,以属性绑定的形式传递到子组件内部,供子组件使用-->
<com1 v-bind:parentmsg="msg"></com1>
</div>
2、JavaScript代码
<script>
//创建 Vue 实例,得到ViewModel
var vm =new Vue({
el:'#app',
data:{
msg:'123 这是父组件'
},
methods:{
},
components:{
// 结论:经过演示,发现,子组件中,默认无法访问到父组件中的 data上的数据和methods中的方法
com1:{
data(){//注意:子组件中的 data 数据,并不是通过父组件传递过来的,而是子组件自身私有的,比如:子组件通过Ajax,请求回来的数据,都可以放到 data 身上;
//data上的数据,都是可读可写的
return {
title:'123',
content:'qqq'
}
},
//注意:组件中的 所有 props 中的数据,都是通过父组件传递给子组件的
//props 中的数据,都是只读的,无法重新赋值
template:'<h1 @click="change">这是子组件 --- {{parentmsg}}</h1>',
props:['parentmsg'],//把父组件传递过来的 parentmsg 属性,先在 props 数组中,定义一下,这样才能使用这个数据
methods:{
change(){
this.parentmsg = "被修改了"
}
}
}
}
})
</script>
父组件把方法传递给子组件(子组件向父组件传值)
- 把方法用v-on绑定在子组件上
- 给input绑定点击事件
- 在点击事件中用this.$exit调用方法
1、html布局
<div id="app">
<!--父组件向子组件传递方法,使用的是事件绑定机制;v-on,当我们自定义了一个 事件属性之后,那么,子组件就能够,通过某些方式,来调用传递进去的这个方法了-->
<com2 v-on:func="show"></com2>
</div>
<template id="tmp1">
<div>
<h1>这是子组件</h1>
<input type="button" value="点击我,获得父组件的值" @click="sonMethod">
</div>
</template>
2、JavaScript代码
<script>
// 定义了一个字面量类型的 组件模板对象
var com2 = {
template:'#tmp1',//通过指定了一个 Id,表示说,要去加载这个指定Id的 template元素中的内容,当做组件的HTML结构
data:function () {
return{
title:123
}
},
methods:{
sonMethod(){
//当点击子组件的按钮的时候,如何拿到父组件传递过来的 func方法,并调用这个方法?
//emit英文原意是触发、调用、发射的意思
this.$emit('func',this.title)
}
}
};
//创建 Vue 实例,得到ViewModel
var vm =new Vue({
el:'#app',
data:{
sonData:''
},
methods:{
show(data){
console.log('这是父组件的数据'+data);
this.sonData = data;
}
},
components:{
// 结论:经过演示,发现,子组件中,默认无法访问到父组件中的 data上的数据和methods中的方法
com2
}
})
</script>
发表评论功能的实现
1、html布局
<div id="app">
<comment-box></comment-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>
<div class="form-group">
<label>评论人</label>
<input type="text" class="form-control" v-model="user"></div>
</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>
2、JavaScript代码
var commentBox = {
template:'#tmp1',
data:function () {
return{
user:'',
content:''
}
},
methods:{
postComment(){
// 1.评论数据存到哪里去?存放到了localStorage中 localStorage.setItem('cmts','')
// 2.先组织出一个最新的评论数据对象
// 3.想办法,把第二步中,得到的评论数据对象,保存到localStorage中;
// 3.1 localstorage 只支持存放字符串数据,要先调用JSON.stringify
// 3.2 在保存最新的评论之前,要先从 localStorage中获取到之前的评论数据(string),转换为一个数组后,把最新的评论unshift到这个数组
// 3.3 如果获取到的 localStorage 中的评论字符串为空不存在,则可以返回一个'[]',让JSON.parse去转换
// 3.4 把最新的评论列表数组,再次调用JSON.stringify 转为数组字符串,然后调用 localStorage.setItem()
var obj = {id:Date.now(),user:this.user,content:this.content}
var list = JSON.parse(localStorage.getItem('cmts')||'[]');
list.unshift(obj);
localStorage.setItem('cmts',JSON.stringify(list));
this.user=this.content='';
}
}
}
var vm =new Vue({
el:'#app',
data:{
list:[
{id:Date.now(),user:'李白',content:'天生我材必有用'},
{id:Date.now(),user:'江小白',content:'劝君更尽一杯酒'},
{id:Date.now(),user:'小马',content:'我姓马'}
]
},
methods:{
},
components:{
commentBox
}
})
</script>
实现评论的发表和自动刷新列表
1、html布局
<div id="app">
<comment-box @func="loadComment"></comment-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>
<div class="form-group">
<label>评论人</label>
<input type="text" class="form-control" v-model="user"></div>
</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>
2、JavaScript代码
<script>
var commentBox = {
template:'#tmp1',
data:function () {
return{
user:'',
content:''
}
},
methods:{
postComment(){
// 1.评论数据存到哪里去?存放到了localStorage中 localStorage.setItem('cmts','')
// 2.先组织出一个最新的评论数据对象
// 3.想办法,把第二步中,得到的评论数据对象,保存到localStorage中;
// 3.1 localstorage 只支持存放字符串数据,要先调用JSON.stringify
// 3.2 在保存最新的评论之前,要先从 localStorage中获取到之前的评论数据(string),转换为一个数组后,把最新的评论unshift到这个数组
// 3.3 如果获取到的 localStorage 中的评论字符串为空不存在,则可以返回一个'[]',让JSON.parse去转换
// 3.4 把最新的评论列表数组,再次调用JSON.stringify 转为数组字符串,然后调用 localStorage.setItem()
var obj = {id:Date.now(),user:this.user,content:this.content}
var list = JSON.parse(localStorage.getItem('cmts')||'[]');
list.unshift(obj);
localStorage.setItem('cmts',JSON.stringify(list));
this.user=this.content='';
this.$emit('func');
}
}
}
var vm =new Vue({
el:'#app',
data:{
list:[
{id:Date.now(),user:'李白',content:'天生我材必有用'},
{id:Date.now(),user:'江小白',content:'劝君更尽一杯酒'},
{id:Date.now(),user:'小马',content:'我姓马'}
]
},
methods:{
loadComment(){
this.list = JSON.parse(localStorage.getItem('cmts')||'[]');
}
},
created(){
this.loadComment();
},
components:{
commentBox
}
})
</script>
使用ref获取DOM元素和组件引用
1、html布局
<div id="app">
<input type="button" value="获取元素" @click="getElement">
<h3 id="myh3" ref="myh3">哈哈哈,今天天气太好了</h3>
<login ref="mylogin" ></login>
</div>
2、JavaScript代码
<script>
var login = {
template:'<h1>登录组件</h1>',
methods: {
show(){
console.log('这是子方法')
}
}
}
var vm =new Vue({
el:'#app',
data:{},
methods: {
getElement(){
this.$refs.mylogin.show();
}
},
components:{
login
}
})
</script>
路由:前端路由和后端路由的概念
什么是路由?
- 后端路由:对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源。
- 前端路由:对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:http请求中不会包含hash相关的内容;所以,单页面程序中的页面跳转主要用hash实现
- 在单页面应用程序中,这种通过hash来切换页面的方式,称作前端路由(区别于后端路由);
相关文件
路由:vue-router的基本使用
1、html布局
<div id="app">
<a href="#/login">登录</a>
<a href="#/register">注册</a>
<!--这是vue-router提供的元素,专门用来 当做占位符的,将来,路由规则,匹配到的组件,就会展示到 这个router-view 中去-->
<!--所以:我们可以把 router-view 认为是一个占位符-->
<router-view></router-view>
</div>
2、JavaScript代码
<script>
// 组件的模板对象
var login = {
template:'<h1>登录组件<h1>'
}
var register = {
template: '<h1>注册组件</h1>'
}
// 2.创建一个路由对象,当导入 vue-router包之后,在window全局对象中,就有了一个路由的构造函数,叫做 VueRouter
// 在new 路由对象的时候,可以为构造函数传递一个配置对象
var routerObj = new VueRouter({
//route //这个配置对象中的 route 表示 【路由匹配规则】的意思
routes:[//路由匹配规则
//每个路由匹配规则,都是一个对象,这个规则对象,身上必须有两个必须的属性;
//属性1 是path ,表示监听哪个路由链接地址
//属性2 是component,表示,如果路由是前面匹配到的path,则展示 component属性对应的那个组件
//注意:component的属性值,必须是一个组件的模板对象,不能是一个组件的引用名称
{path:'/login',component:login},
{path:'/register',component:register}
]
})
var vm =new Vue({
el:'#app',
data:{},
methods: {
},
router:routerObj//将路由规则对象,注册到vm实例上,用来监听URL地址的变化,然后展示对应的组件
})
</script>
路由:vue-link的使用
为什么要使用router-link?
因为官方是不建议手动打#号的。
1、html布局
<div id="app">
<!--<a href="#/login">登录</a>-->
<!--<a href="#/register">注册</a>-->
<!--router-link默认渲染为一个 a标签-->
<!--也可以通过tag="span"渲染为一个span标签,但是不管渲染为什么标签,在router-link内部永远为他绑定了一个点击的触发事件,去实现路由的切换-->
<router-link to="/login" tag="span">登录</router-link>
<router-link to="/register">注册</router-link>
<router-view></router-view>
</div>
路由:redirect重定向的使用
为什么要使用redirect?
强制展示某个组件
1、JavaScript代码
<script>
// 组件的模板对象
var login = {
template:'<h1>登录组件<h1>'
}
var register = {
template: '<h1>注册组件</h1>'
}
// {path:'/',component:login},
//不推荐,因为会让用户对根路径和登录组件产生误解
{path:'/',redirect:'/login'},//这里的 redirect 和 Node中的redirect完全是两码事
{path:'/login',component:login},
{path:'/register',component:register}
]
})
var vm =new Vue({
el:'#app',
data:{},
methods: {
},
router:routerObj//将路由规则对象,注册到vm实例上,用来监听URL地址的变化,然后展示对应的组件
})
</script>
设置选中路由高亮的两种方式
- 用默认类设置
<style>
.router-link-active{
color: red;
font-weight: 800;
font-style: italic;
font-size: 80px;
text-decoration: underline;
background-color: green;
}
</style>
- 用自定义类
linkActiveClass:'类名’
<script>
// 组件的模板对象
var login = {...}
var routerObj = new VueRouter({
routes:[ ... ],
linkActiveClass:'myactive'
})
var vm =new Vue({... })
</script>
为路由切换启动动画
- 把router-view放在transition内部
- style设置动画
1、html布局
<div id="app">
<router-link to="/login" tag="span">登录</router-link>
<router-link to="/register">注册</router-link>
<transition mode="out-in">
<router-view></router-view>
</transition>
</div>
2、css样式
<style>
.router-link-active,.myactive{
color: red;
font-weight: 800;
font-style: italic;
font-size: 80px;
text-decoration: underline;
background-color: green;
}
.v-enter,
.v-leave-to{
opacity: 0;
transform: translateX(140px);
}
.v-enter-active,
.v-leave-active{
transition:all 0.5s ease;
}
</style>
使用query方式传递参数(方式1)
1、html布局
<div id="app">
<!--如果在路由中,使用查询字符串给路由传递参数,则不需要修改路由规则的 path属性-->
<!--传递两个参数就用&连接-->
<router-link to="/login?id=10&name=wh" tag="span">登录</router-link>
<router-link to="/register">注册</router-link>
<router-view></router-view>
</div>
2、JavaScript代码
<script>
// 组件的模板对象
var login = {
template:'<h1>登录组件---{{$route.query.id}}---{{$route.query.name}}</h1>',
created(){//组件的生命周期钩子函数
// console.log(this.$route.query.id);
}
}
var register = {
template: '<h1>注册组件</h1>'
}
var routerObj = new VueRouter({
routes:[
{path:'/login',component:login},
{path:'/register',component:register}
]
})
var vm =new Vue({
})
</script>
使用params方式传递参数(方式2)
1、html布局
<div id="app">
<!--注意,传的值的个数要和path的参数一一对应-->
<!--多个是用/-->
<router-link to="/login/12/wh" tag="span">登录</router-link>
<router-link to="/register">注册</router-link>
<transition>
<router-view></router-view>
</transition>
</div>
2、JavaScript代码
<script>
// 组件的模板对象
var login = {
template:'<h1>登录组件</h1>',
created(){
console.log(this.$route.params.id)
console.log(this.$route.params.name)
}
}
var register = {
template: '<h1>注册组件</h1>'
}
var routerObj = new VueRouter({
routes:[
{path:'/login/:id/:name',component:login},
{path:'/register',component:register}
]
})
var vm =new Vue({
})
</script>
使用children属性实现路由嵌套
1、html布局
<div id="app">
<router-link to="/account">Account</router-link>
router
<!--router-view是一个容器,装载的的account内部的内容-->
<router-view></router-view>
</div>
<template id="tmp1">
<div>
<h1>这是Account组件</h1>
<router-link to="/account/login">登录</router-link>
<router-link to="/account/register">注册</router-link>
<!--router-view是一个容器,装载的是login组件或者register组件-->
<router-view></router-view>
</div>
</template>
2、JavaScript代码
<script>
// 组件的模板对象
var account = {
template:'#tmp1'
}
var login = {
template:'<h3>登录</h3>'
}
var register = {
template:'<h3>注册</h3>'
}
//创建 Vue实例,得到ViewModel
var router = new VueRouter({
routes:[
{
path:'/account',
component:account,
// 使用children属性,实现子路由,同时,子路由的path前面,不要带/,否则永远以根路径开始请求,这样不方便我们用户去理解URL地址
children:[
{path:'login',component: login},
{path:'register',component:register}
]
}
]
})
var vm =new Vue({
el:'#app',
data:{},
methods: {},
router:router//将路由规则对象,注册到vm实例上,用来监听URL地址的变化,然后展示对应的组件
})
</script>
使用命名视图实现经典布局
1、html布局
<div id="app">
<router-view></router-view>
<!--这些命名字符的名称是字符串-->
<router-view name="left"></router-view>
<router-view name="main"></router-view>
</div>
2、JavaScript代码
<script>
var header = {
template:'<h1>Header头部区域</h1>'
}
var leftBox = {
template: '<h1>Left侧边栏区域</h1>'
}
var mainBox = {
template:'<h1>Main主体区域</h1>'
}
// 创建路由对象
var router = new VueRouter({
routes:[
{path:'/',components:{
default:header,
left:leftBox,
main:mainBox
}}
]
})
var vm =new Vue({
el:'#app',
data:{},
methods: {},
router:router//将路由规则对象,注册到vm实例上,用来监听URL地址的变化,然后展示对应的组件
})
</script>