vue2.x学习记录
引包、留坑、实例化、插值表达式
-
引包
-
npm install vue—安装vue
-
从下载的vue包中找到vue.js, 并在页面引入
<script src="vue.js"></script>
-
-
留坑 即留一个vue模板插入的地方或是vue代码对其生效的地方
-
实例化 即启动vue
启动: new Vue({el:目的地, template:模板内容}); 实例化传入的是一个对象options
- options
- 目的地 el 对应上面留坑的坑位, 可通过id名, 类名, 标签名来查找.
- 内容 template
- 数据 data 值为函数形式也可是对象, 但都是用函数, 因为用的函数最后也是return一个对象
- options
-
插值表达式
- 插值表达式内填入data里面的变量即可在页面取到变量值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="vue.js"></script>
<script>
new Vue({
// el是vue的目的地,即vue将被应用到何处,#app即id选择器
el:'#app',
// 运行后,<div id="app"></div>将被下面的模板替换掉
template:`
<div>
<div>我这里是模板内容 </div>
<div>111</div>
</div>
`,
// 值--可通过插值的方式绑定到html
data:function(){
return {
msg:'Hello Vue!'
}
}
})
</script>
</html>
常用指令
指令
- 在vue中提供一个对于页面+数据的更为方便的操作, 这些操作就是指令
- 例如:
<div v-xxx=''></div>
- 例如:
- 在vue中v-xxx就是vue的指令
- 指令就是以数据去驱动DOM行为的, 简化DOM操作
常用指令
- v-text 其实就是为元素的innerText赋值, 必须是双标签
- v-html 其实就是为元素的innerHTML赋值 —可以解析html
- v-if 判断是否插入, 对应append和remove
- v-else-if
- v-else
- v-show 判断是否隐藏 对应display: none
- v-for
- 数组 item index
- 对象 value key index
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script>
new Vue({
el:'#app',
template:`
<div>
<div v-text='mytext'></div>
</hr>
<div v-html='myhtml'></div>
<button v-if='num==1'>测试v-if</button>
<div v-show='checkshow'></div>
<ul>
<li v-for='item in arrayfor'>
</li>
<li v-for='(item,index) in arrayfor'>
--
</li>
</ul>
<ul>
<li v-for='(oj,key,value) in ojfor'>
:--
</li>
</ul>
</div>
`,
data:function(){
return {
mytext:'<h1>这是v-text</h1>',
myhtml:'<h1>这是v-html</h1>',
num: 1,
checkshow:false,
// v-for可用于数组和对象, 写法基本相似
// 对数组而言, item是某一项, index是对象的下标
arrayfor:['篮球','足球','乒乓球'],
// 对对象而言, item是某一项的值,key是值对应的键, vlaue是索引(下标)
ojfor:{play:'篮球',people:'阿三',age:'19'}
}
}
})
</script>
</html>
vue单双向数据流及事件绑定
vue单向数据流绑定属性值v-bind:(属性) 简写 : (属性)
例子: <input v-bind:value="name" v-bind:class="name">
- 单向数据绑定: 内存改变影响页面改变
- v-bind 就是对属性的简单赋值, 当内存中值改变, 会触发重新渲染
vue双向数据流 v-model 只作用于有value属性的元素
例子: <input v-model="name" v-bind:class="name">
- 双向数据绑定 页面对于input的value改变, 是能影响内存中的name变量的
- 内存js改变name的值, 会影响页面重新渲染最新值
| **事件绑定v-on:事件名=”表达式 | 函数名” 简写 @事件名=”表达式 | 函数名”** |
- 事件名可以是原生也可以是自定义的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script>
new Vue({
el:'#app',
// 在模板中获取data中的变量是不需要this的
template:`
<div>
单向数据绑定v-bind
<input type='text' v-bind:value="name" :class="name"><br>
双向数据绑定v-model
<input type='text' v-model="name"></br>
<button v-on:click="name='这是新值'">点击改变值1</button>
<button @click="change">点击改变值2</button>
</div>
`,
data:function(){
return {
name:'hello'
}
},
methods:{
change:function(){
this.name="通过方法改变的新值"
}
}
})
</script>
</html>
**注意: **
vue双向数据绑定
- vue对数组的双向绑定仅支持数组的7个api
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
- 直接通过下标更改数组是不会触发双向绑定的, 这时就需要使用$set()方法
过滤器
- 过滤器是可以对我们的数据进行添油加醋后再显示
- 过滤器有全局过滤器和组件内的过滤器
- 全局过滤器Vue.filter(‘过滤器名’, 过滤方式fn );
- 组件内的过滤器 filters: { ‘过滤器名’, 过滤方式fn }
-
- 最终都是在过滤方式fn里return产出最终的数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
我输入的: <input type="text" name="" v-model='instring'></br>
我输出的: </br>
翻转输出: </br>
</div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script>
// 全局的过滤器--reversal必须用''包起来, 否则会被认为是个变量而不是方法名
Vue.filter('reversal',function(val,arg2 = 0){
var str='';
if(arg2!==0)
str=arg2+val.split('').reverse().join('')
else
str=val.split('').reverse().join('')
return str
})
new Vue({
el:'#app',
data(){
return {
instring:''
}
},
// 组件内的过滤器
filters:{
// 不同函数名实现方式
reversal1(val){
// 字符串转数组 翻转 数组转字符串
return val.split('').reverse().join('')
},
reversal2(val,arg2){
return arg2+val.split('').reverse().join('')
},
//同一函数名实现方式, 类似重载
// js中的重写函数意味着覆盖, 所以不能用其他语言的重写函数方式来实现重载
reversal(val,arg2 = 0){
var str='';
if(arg2!==0)
str=arg2+val.split('').reverse().join('')
else
str=val.split('').reverse().join('')
return str
}
}
})
</script>
</html>
vue中的this是vue封装好给我们使用的, 跟平常方法里面的this是不同的


数据监听watch计算属性computed
watch监听单个, computed监听多个
思考业务场景:
- 类似淘宝, 当我输入某个人名时, 我想触发某个效果
- 利用vue做一个简单的计算器
当watch监听的是复杂数据类型时, 需要做深度监听 (写法如下)
watch: {
msg:{
handler(val){
if(val.text=='love'){
alert(val.text)
}
},
deep: true //开启深度监听
}
}
computed 监听对象, 写在了函数内部, 凡是函数内部有this.相关属性, 改变都会触发当前函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<div>watch监听数据</div>
<input type="text" name="" v-model="msg.text" />
<div>computed监听数据</div>
(<input type="text" name="" v-model="n1">+
<input type="text" name="" v-model="n2">)*
<input type="text" name="" v-model="n3">=
</div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script>
new Vue({
el: "#app",
data() {
return {
msg: { text: "" },
n1:'',
n2:'',
n3:'1'
};
},
// computed里面监听的任何一个 this.变量 发生变化都会触发监听函数
computed: {
result() {
return (Number(this.n1)+Number(this.n2))*Number(this.n3);
},
},
watch: {
msg: {
handler(newval, oldval) {
if (newval.text == "love") {
alert(newval.text);
}
},
deep: true,
},
},
});
</script>
</html>
组件化开发
-
创建组件的两种方式
-
var Header = { template:'模板', data是一个函数, methods:功能, components:子组件们 } //局部声明 -
Vue.component('组件名',组件对象); //全局注册 等于注册加声明了
-
- 组件类型
- 通用组件 (例如表单、弹窗、布局类等)
- 业务组件 (抽奖、机器分类)
- 页面组件 (单页面开发程序的每个页面都是一个组件、只完成功能、不复用)
- 组件开发三部曲: 声明、注册、使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
</div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script>
// 1.组件局部声明
var MyHeader= {
template: `
<div>头部</div>
`,
}
var MyBody= {
template: `
<div>身体</div>
`
}
//曾经的组件局部声明写法:
// var myBody= Vue.extend({
// template: `
// <div>身体</div>
// `
// })
//1. 2.组件全局注册(声明+注册)
Vue.component('MyFooter',{
template:`
<div>尾部</div>
`
});
new Vue({
el: '#app',
// 2.组件局部注册
components: {
MyHeader,
MyBody
},
//3.组件使用
template: `
<div>
<my-header></my-header>
<my-body></my-body>
<my-footer></my-footer>
</div>
`,
data() {
return { }
}
})
</script>
</html>
slot插槽和ref、$parent
- slot插槽
- slot就是子组件里给DOM留下的坑位
- 任何位置都可以使用: <子组件>DOM子组件>
- slot是动态的DOM
- ref获取子组件实例
- 识别: 在子组件或元素上使用属性 ref=”xxx”
- 获取: this.$refs.xxx 获取元素
- $el 是拿到其DOM
- $parent获取父组件实例 (可在子组件直接使用this.$parent即可)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script>
// 子父组件都可以获取彼此的实例,变量,方法,DOM--实现互相通信
var Child = {
template: `
<div>子组件</div>
`,
data() {
return {
msg: 'hello'
}
},
//子组件通过$parent获取父组件
created() { //数据加载完毕生命周期钩子函数
//获得父组件实例
console.log(this.$parent)
}
}
var Parent = {
//模板中, 父组件通过ref获取子组件
template: `
<div>
父组件
<slot name='hello'></slot>
<child ref='childs'></child>
</div>
`,
components: {
Child
},
data() {
return {
parents: '我父组件'
}
},
//父组件中通过refs获取子组件
mounted() {//dom挂载完毕时的生命周期钩子函数
//this.$refs.childs即可获取到子组件实例,接着可进一步获取其内容,
//比如.$el就是获取其DOM 子组件中的msg同样可以通过其他方法获取到
console.log(this.$refs.childs.$el)
//输出: <div>子组件</div>
},
}
new Vue({
el:'#app',
components:{
Parent
},
// 插槽内容1不会显示,因为父组件中的插槽指定了name
template:`
<div>
<parent>
<div>插槽内容1</div>
<div slot='hello'>插槽内容2</div>
</parent>
</div>
`,
data(){
return {}
}
})
</script>
</html>
父子组件通信
- 父传子
- 父用子的时候通过属性传递
- 子要声明 props : [ ‘属性名’ ] 来接收
- 收到后就是自己的了, 随便怎么用
- 可在template中直接用
- 可在js中 this.属性名 用
-
子传父
-
子组件里通过 $emit( ‘自定义事件名’, 变量1, 变量2 ) 触发
-
父组件 @自定义事件名= ‘事件名’ 监听
-
子组件方法里: this.$emit('sendfather', val1, val2) 触发自定义事件 父组件里: <child @sendfather = 'mymethods'></child> 同时父组件要在data里定义用于接收子组件传来数据的变量(vue不允许父组件直接使用接收到的数据,而是先将数据存进data再使用)
-
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script>
//父传子: 子组件定义好 props, 直接使用即可(但子组件定义要在父组件前面)
var Child = {
template: `
<div>子组件
<button @click='sendparent'>我要为父组件反馈东西</button>
</div>
`,
props: ['sendchild'],
methods: {
sendparent() {
//子传父: baba 就是子组件向父组件反馈信息的事件名
this.$emit('baba', '子组件传来的数据','数据2');
},
},
}
//父传子: 父组件通过属性sendchild(子组件定义好的)传递数据给子组件
var Parent = {
//子传父: 父组件通过监听子组件的'baba'事件来接收值
template: `
<div>父组件
<child sendchild='父组件传来的' @baba='reserve'></child>
</div>
`,
components: {
Child
},
data(){
return {
//子传父: 用于接收子组件数据的变量
msg1:'',
msg2:''
}
},
methods: {
//子传父: 父组件中用于接收子组件数据的事件
reserve(val1, val2) {
this.msg1 = val1
this.msg2 = val2
},
},
}
new Vue({
el:'#app',
components: {
Parent
},
template: `
<div>
<parent></parent>
</div>
`,
data(){
return {}
}
})
</script>
</html>
非父子组件之间的通信
-
创建一个空实例 (bus[命名自定义]中央事件总线也可叫中间组件)
-
利用 $emit $on 的触发和监听事件实现非父子组件的通信
Vue.prototype.$bus = new Vue() //在vue上面挂载一个$bus作为中央处理组件 this.$bus.$emit('自定义事件名', '传递的数据') //触发自定义事件传递数据 this.$bus.$on('自定义事件名', fn) //监听自定义事件获取数据 -
解决方案还有 vuex(多用于大型项目)、provide/inject(vue2.5之后新增)是解决同根往下派发、本地存储也可以进行非父子组件之间的通信
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script>
Vue.prototype.$bus = new Vue()
var MyHeader = {
template: `
<div>
头部
</div>
`,
data(){
return {
headermsg: '头部信息'
}
},
created() {
//将执行vue的this存起来, 因为函数的中this是指向函数内的
// var self = this
// self.$bus.$on('sending', function(val){
// self.headermsg = val
// })
//如果使用箭头函数, 就不必存储this了, 因为箭头函数
//会将函数内的this指向到函数外部
this.$bus.$on('sending',val=>{
this.headermsg = val
})
},
}
var MyBody = {
template: `
<div>身体</div>
`,
}
var MyFooter = {
template: `
<div>底部<button @click='sendhead'>向头部传送数据</button></div>
`,
methods: {
sendhead() {
this.$bus.$emit('sending','底部的数据')
},
},
}
new Vue({
el:'#app',
components:{
MyHeader,
MyBody,
MyFooter
},
template:`
<div>
<my-header></my-header>
<my-body></my-body>
<my-footer></my-footer>
</div>
`,
})
</script>
</html>
Vue的生命周期
- 需要频繁的创建和销毁组件
- 比如页面中部分内容显示与隐藏, 但是用的是 v-id
- 组件缓存
- 内置组件中 ==
== - 被其包裹的组件, 在 v-if = false 的时候, 不会销毁, 而是停用
- v-if = true 不会创建, 而是激活
- 避免频繁创建组件对象的性能损耗
- 组件的激活和停用
- activated 和 deactivated
- 内置组件中 ==
-
成对比较
- created 和 beforeCreate — 数据加载后 数据加载完毕
- A 可以操作数据 B 数据没有初始化
- mounted 和 beforeMount —-dom挂载完毕 dom挂载前
- A 可以操作DOM B 还未生成DOM
- updated 和 beforeUpdate —数据更新后 数据更新前
- A 可以获取最终数据 B 可以二次修改
- destroyed 和 beforeDestroy –组件销毁后 组件销毁前
- 性能调优: 频繁销毁创建的组件使用内置组件
<keep-alive></keep-alive>包裹
- 性能调优: 频繁销毁创建的组件使用内置组件
- created 和 beforeCreate — 数据加载后 数据加载完毕
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script>
var Test = {
template: `
<div>Test组件
<button @click="msg+='1'">msg+1</button>
</div>
`,
data() {
return {
msg: 'Hello Vue'
}
},
//组件创建前--数据(data)未初始化
beforeCreate() {
console.log('组件创建前')
console.log(this.msg)
},
//组件创建后--数据加载完毕
created() {
console.log('组件创建后')
console.log(this.msg)
},
//DOM挂载前--模板还未渲染到dom中
beforeMount() {
console.log('Dom挂载前')
console.log(document.body.innerHTML)
},
//DOM挂载后--模板渲染完毕
mounted() {
console.log('Dom挂载后')
console.log(document.body.innerHTML)
},
//数据(data)更新前
beforeUpdate() {
console.log('数据更新前')
console.log(document.body.innerHTML)
},
//数据(data)更新后
updated() {
console.log('数据更新后')
console.log(document.body.innerHTML)
},
//组件销毁前
beforeDestroy() {
console.log('组件销毁前')
},
//组件销毁后
destroyed() {
console.log('组件销毁后')
},
//如果用<keep-alive></keep-alive>包裹组件
//那么在v-if值变化时, 不再是销毁而是停用
//组件停用
deactivated() {
console.log('组件停用')
},
//组件激活
activated() {
console.log('组件激活')
},
//对于需要动态隐藏/显示的组件可以使用keep-alive提高性能
}
new Vue({
el: '#app',
components: {
Test
},
template: `
<div>
<keep-alive><test v-if='testshow'></test></keep-alive></br>
<button @click='clickbtn'>销毁组件</button>
</div>
`,
data() {
return {
testshow: true
}
},
methods: {
clickbtn() {
//如果是true则变为false, 如果是false则变为true
this.testshow = !this.testshow
},
},
})
</script>
</html>
路由的跳转原理 ( 哈希模式 )
- 单页应用的路由模式有两种
- **哈希模式: ** 利用
hashchange事件监听 url 的hash 的改变 - **history模式: ** 使用此模式需要后台配合把接口到打到我们打包后的index.html上
- **哈希模式: ** 利用
-
哈希模式原理
window.addEventListener('hashchange', function(e){ console.log(e) })核心是锚点值的改变, 我们监听到锚点值改变了就去局部改变页面数据, 不能跳转. 跟传统开发模式url改变后 立刻发起请求, 响应整个页面, 渲染整个页面比路由的跳转用户体验更好
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 路由跳转本质是锚点,就是# -->
<a href="#/login">登录</a>
|
<a href="#/register">注册</a>
<div id="app"></div>
</body>
<script>
var appdiv=document.getElementById('app')
window.addEventListener('hashchange', function(e){
console.log(location.hash)
switch(location.hash){
case '#/login':
appdiv.innerHTML = '这是登录页面';
break;
case '#/register':
appdiv.innerHTML = '这是注册页面';
break;
}
})
</script>
</html>
安装和使用路由
-
路由是以插件的形式引入到我们的vue项目中的
-
vue-router是vue的核心插件
-
1: 下载
npm i vue-router -S(将node_modules/dist/vue-router.js复制到你的项目下并js引入) -
2: 安装插件
Vue.use(VueRouter); -
3: 创建路由对象
var router = new VueRouter(); -
4: 匹配路由规则
router.addRoutes([路由对象]);路由对象
{path:'锚点值', component: 要(填坑)显示的组件} - 5: 将配置好的路由对象交给Vue
- 在 options 中传递-> key 叫做 router
- 6: 留坑(使用组件)
<router-view></router-view>
-
-
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script src="./vue-router.js"></script>
<script>
var Login = {
template: `
<div>登录页面</div>
`,
}
//安装路由插件
Vue.use(VueRouter);
//创建路由对象
var router = new VueRouter({
//配置路由对象
routes: [
{path: '/login', name: 'login', component: Login}
]
//将浏览器上的路由改为....#/login即可访问到
})
new Vue({
el: '#app',
router,
template: `
<div>
<router-view></router-view>
</div>
`,
data() {
return {
};
},
})
</script>
</html>
路由的跳转
**路由的跳转方式有: **
- **通过标签: **
<router-link to='/login'></router-link> - **通过js控制跳转: **
this.$router.push({path:'/login'})
**区别: **
this.$router.push()跳转到指定的url, 会向history插入新记录
this.$router.replace() 同样是跳转到指定的url, 但是这个方法不会向history里面添加新的记录, 点击返回, 会跳转到上上一个页面, 上一个记录是不存在的.
this.$router.go(-1) 常用来做返回, 读history里面的记录后退一个
**vue-router中的对象: **
- **$route ** 路由信息对象, 只读对象
- $router 路由操作对象, 只写对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script src="../1-13路由vue-router使用/vue-router.js"></script>
<script>
var Login = {
template: `
<div>登录页面</div>
`,
}
var Register = {
template: `
<div>注册页面</div>
`,
}
//安装路由插件
Vue.use(VueRouter);
//创建路由对象
var router = new VueRouter({
//配置路由对象
routes: [
{path: '/login', name: 'login', component: Login},
{path: '/register', name: 'register', component: Register}
]
//将浏览器上的路由改为....#/login即可访问到
})
new Vue({
el: '#app',
router,
template: `
<div>
<router-link to='/login'>去登录</router-link>
|
<router-link to='/register'>去注册</router-link>
<div>
<button @click='goregister'>去注册</button>
<button @click='back'>返回上一页</button>
</div>
<router-view></router-view>
</div>
`,
data() {
return {
};
},
methods: {
goregister() {
//push跟replace是达到同样效果, 但是replace是不会向history插入记录
// this.$router.replace({path:'/register'})
this.$router.push({path:'/register'})
},
//返回上一页,读history里面记录的后退一个
back(){
this.$router.go(-1)
}
},
})
</script>
</html>
路由的传参和取参
-
查询参
-
配置 ( 传参 ) ** **:to=”{ name : ‘login’, query : {id : loginid} }”
-
获取 ( 取参 ) ** **this.$route.query.id
-
-
路由参数
-
配置 ( 传参 ) :to=”{ name : ‘register’ , params : {id : registerid} }”
-
配置路由的规则 { name : ‘detail’ , path : ‘/detail
/:id’ } -
获取 this.$route.params.id
-
**总结: **
- :to 传参的属性里 params是和name配对的 query和name或path都可以
- 使用路由参数必须要在配置路由规则里面配置好参数名, 否则刷新页面参数会丢失
补充:
==如果希望路由相同而参数不同仍能够动态显示不同内容(即刷新),那就需要为router-view添加:<router-view :key="this.$route.fullPath"></router-view>==
建议都使用name, 因为无论是params还是query都可以与name配对
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script src="../1-13路由vue-router使用/vue-router.js"></script>
<script>
var Login = {
template: `
<div>登录页面</div>
`,
data() {
return {
msg: ''
}
},
//获取查询参(类似 :id=123 )
created() {
this.msg = this.$route.query.id
},
};
//获取路径参有两种方法: 法一
var Register = {
template: `
<div>注册页面</div>
`,
data() {
return {
registerfoo: ''
}
},
created() {
this.registerfoo = this.$route.params.foo
}
};
//法二 --(需要在配置路由对象时添加: props:true)
var Buy = {
template: `
<div>购买页面</div>
`,
props:['fzz']
};
//安装路由插件
Vue.use(VueRouter);
//创建路由对象
var router = new VueRouter({
//配置路由对象
routes: [
{ path: "/login", name: "login", component: Login },
{ path: "/register/:foo", name: "register", component: Register },
{ path: "/buy/:foo", name: "buy", props:true, component: Buy },
],
//将浏览器上的路由改为....#/login即可访问到
});
new Vue({
el: "#app",
router,
// 传参: 查询参和路由参(路由参需要在配置路由对象时加以配置)
template: `
<div>
<router-link
:to="{name:'login',query:{id:'123'}}">去登录</router-link>
|
<router-link
:to="{name:'register',params:{foo:'bar'}}">去注册</router-link>
|
<router-link
:to="{name:'buy',params:{fzz:'haha'}}">去购物</router-link>
|
<button @click='jslink'>js去登录</button>
<router-view :key="this.$route.fullPath"></router-view>
</div>
`,
data() {
return {};
},
methods: {
goregister() {
//push跟replace是达到同样效果, 但是replace是不会向history插入记录
// this.$router.replace({path:'/register'})
this.$router.push({ path: "/register" });
},
//返回上一页,读history里面记录的后退一个
back() {
this.$router.go(-1);
},
//js跳转传参也是一样的
jslink() {
this.$router.push({name:'login', query:{id: '456'}})
//希望通过传入的参数不同显示不同内容时, 一定要为router-view添加一个key,并传入路径的完整值(包含参数),这样即便只是参数发送变化,也能够识别到锚点变化: <router-view :key="this.$route.fullPath"></router-view>
}
},
});
</script>
</html>
嵌套路由
-
代码思想
- 1. router-view的细分
- router-view第一层中, 包含一个
router-view
- router-view第一层中, 包含一个
-
2. 每一个坑挖好了, 要对应单独的组件
-
路由配置
-
routes: [ { path: '/nav', name: 'nav', component: Nav, //路由嵌套增加此属性 children:[ //在这里配置嵌套的子路由 ] } ]
-
- 1. router-view的细分
-
案例
- 进入首页下面会有导航, 个人中心, 首页, 咨讯, 我的 之类的标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="../1-2引包,留坑,实例化,插值/vue.js"></script>
<script src="../1-13路由vue-router使用/vue-router.js"></script>
<script>
var Nav = {
//<router-view></router-view>是路由入口, 因为子路由也需要入口,所以这里也要加<router-view></router-view>
template: `
<div>
<router-view></router-view>
<router-link :to= "{name: 'nav.index'}">首页</router-link>
|
<router-link :to= "{name: 'nav.personal'}">个人中心</router-link>
|
<router-link :to= "{name: 'nav.message'}">资讯</router-link>
|
<router-link :to= "{name: 'nav.mine'}">我的</router-link>
</div>
`,
}
var Index = {
template: `
<div>首页</div>
`,
}
var Personal = {
template: `
<div>个人中心</div>
`,
}
var Message = {
template: `
<div>资讯</div>
`,
}
var Mine = {
template: `
<div>我的</div>
`,
}
//安装路由插件
Vue.use(VueRouter);
//创建路由对象
var router = new VueRouter({
//配置路由对象
routes: [
{
path: '/nav',
name: 'nav',
component: Nav,
//嵌套路由增加这个属性
children: [
//配置嵌套路由
//重定向, 如果到了/nav,则自动重定向到/nav/index
{path: '', redirect: '/nav/index'},
{path: 'index', name: 'nav.index', component: Index},
{path: 'personal', name: 'nav.personal', component: Personal},
{path: 'message', name: 'nav.message', component: Message},
{path: 'mine', name: 'nav.mine', component: Mine},
]
}
]
})
new Vue({
el: '#app',
router,
template: `
<div>
<router-link to='/nav'>去标签页</router-link>
<router-view></router-view>
</div>
`,
data() {
return {
}
}
})
</script>
</html>
路由守卫
const router = new VueRouter({ ... })
//前置的钩子函数 最后要执行next()才会跳转
router.beforeEach((to, from, next) => {
// ...
})
//后置的钩子函数 已经跳转了不需要next
router.afterEach((to, from) => {
// ...
})
主要了解: **路由守卫主要用于检测是否登录, 没登录就跳转到登录页面不让用户在其他页面停留, 但现在这种处理主要都用请求的全局拦截来做了. **
//沿用上一节的代码,仅仅在 new Vue中增加以下几行:
methods: {
},
mounted() {
//to指的是到哪里去, from是从哪里来, next是放行
router.beforeEach((to, form, next)=>{
console.log(to)
//如果目的路径是/nav/index才可以跳转
if(to.path == '/nav/index'){
next()
}
})
},
小实战—补充知识
-
return this.chatarr.filter(v => v.active).length;
filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或等价于 true 的值的元素创建一个新数组。
-
本地存储
window.localStorage.setItem(‘chat’, JSON.stringify(this.chatarr))
this.chatarr = JSON.parse(window.localStorage.getItem(‘chat’))
-
提示框
window.confirm(
是否删除${this.chatarr[index].text}?) -
const result = this.chatarr.find((v) => v.text == goods.text);
find方法对数组中的每一项元素执行一次 callback 函数,直至有一个 callback 返回 true。当找到了这样一个元素后,该方法会立即返回这个元素的值,否则返回 undefined。
利用插槽封装组件—更详细的插槽解释
-
留坑
-
要封装的组件:
navigation-link<a v-bind:href="url" class="nav-link" > <slot></slot> </a> -
使用封装好的组件:
<navigation-link url="/profile"> <!-- 添加一个 Font Awesome 图标 --> <span class="fa fa-user"></span> Your Profile </navigation-link> -
组件中
<slot></slot>在渲染时将被替换为新填入的内容:<a v-bind:href="url" class="nav-link" > <!-- 添加一个 Font Awesome 图标 --> <span class="fa fa-user"></span> Your Profile </a> -
可以填入任何内容, 包括其他的组件
-
-
编译作用域
-
==父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。==
-
可以这样写:
<navigation-link url="/profile"> Logged in as </navigation-link> -
但不能这样写:
<navigation-link url="/profile"> Clicking here will send you to: <!-- 这里的 `url` 会是 undefined,因为其 (指该插槽的) 内容是 _传递给_ <navigation-link> 的而不是 在 <navigation-link> 组件*内部*定义的。 --> </navigation-link>
-
-
为插槽准备后备内容(即默认内容)
-
submit-button组件<button type="submit"> <slot>Submit</slot> </button> -
如果直接
<submit-button></submit-button>, 那么插槽内就会渲染Submit, 如果使用时填入了其他内容, 插槽内会渲染填入的内容, 不会渲染后备内容
-
-
具名插槽(为插槽指定name)
-
带有多个插槽的
base-layout组件<div class="container"> <header> <!-- 我们希望把页头放这里 --> <slot name="header"></slot> </header> <main> <!-- 我们希望把主要内容放这里 --> <slot></slot> </main> <footer> <!-- 我们希望把页脚放这里 --> <slot name="footer"></slot> </footer> </div>**不带name的
<slot>会带有隐含的name ->default** -
现在我们就可以在
<template>元素上使用v-slot指令并提供参数来指定一个插槽<base-layout> <template v-slot:header> <h1>Here might be a page title</h1> </template> <p>A paragraph for the main content.</p> <p>And another one.</p> <template v-slot:footer> <p>Here's some contact info</p> </template> </base-layout>其中没有被包裹在带有
v-slot的<template>中的内容都会被视为默认插槽的内容, 或者也可以将这些内容包裹在<template v-slot:default></template>中, 因为solt有隐含的name
-
-
作用域插槽
-
如果我们想让插槽内容访问子组件中data, 那我们就需要将子组件的数据绑定到
slot上,vurrent-user组件:<span> <slot v-bind:user="user"> </slot> </span> -
在父级作用域中, 使用带值的
v-slot来定义插槽prop(user)的名字<current-user> <template v-slot:default="mySlotProps"> </template> </current-user>上面我们将包含所有插槽prop的对象命名为
mySlotProps, 当然也可以命名为其他名字
-
-
独占默认插槽的缩写语法和具名插槽缩写语法
-
就像上例的组件, 它只有一个默认插槽, 那我们在父级作用域中就可以这样书写(更简洁):
<current-user v-slot:default="mySlotProps"> </current-user>**当然, 默认插槽的name也可以省略: **
<current-user v-slot="mySlotProps"> </current-user>==注意: 默认插槽的缩写语法不能和具名插槽混用,只要出现多个插槽, 请始终使用完整的
<template>语法==v-slot也有缩写形式, 就是:#<current-user #default="mySlotProps"> </current-user>==但请注意, 如果你这样写是会触发警告的: <current-user #=”{ mySlotProps}”>, 也就是说,
#缩写使用于使用具名插槽name的情况.==
-
-
结构插槽
Prop-
上例中我们需要写 ``, 这个属性访问也太长了, 当然有简写:
<current-user #default="{ user }"> </current-user> -
为什么可以这样写? 其实作用域插槽的内部工作原理是将你的插槽内容包裹在一个拥有单个参数的函数里:
function (mySlotProps) { // 插槽内容 }这就表明,
v-slot的值可以是任何能够作为函数参数的JS表达式, 那当然可以使用ES2015解构表达式了 -
解构表达式远不止提供缩写那么简单, 它也开启了
prop重命名功能<current-user #default="{ user: person }"> </current-user>甚至可以定义后备内容(当插槽
prop是undefined时, 非常有用)<current-user #default="{ user = { firstName: 'Guest' } }"> </current-user>
-
-
动态插槽名
动态指令参数也可以用在v-slot上, 这就实现了动态插槽名<base-layout> <template v-slot:[dynamicSlotName]> ... </template> </base-layout> <!-- 最终dynamicSlotName(变量)会被替换为它的值 --> -
一个
<todo-list>组件例子, 它是一个列表且包含布局和过滤逻辑<ul> <li v-for="todo in filteredTodos" v-bind:key="todo.id" > <!-- 我们为每个 todo 准备了一个插槽, 将 `todo` 对象作为一个插槽的 prop 传入。 --> <slot name="todo" v-bind:todo="todo"> <!-- 后备内容 --> </slot> </li> </ul>使用: 可以选择为 todo 定义一个不一样的
<template>作为替代方案,并且可以从子组件获取数据:<todo-list v-bind:todos="todos"> <template v-slot:todo="{ todo }"> <span v-if="todo.isComplete">✓</span> </template> </todo-list>