【尚硅谷】2021最新Vue技术全家桶丨vue3.x最新版详细讲解
示例对应 code web
DOCTYPE html>
<body>
<div id="demo">
<h1>Hello,{{name.toUpperCase()}},{{address}}h1>
div>
<script type="text/javascript" >
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//创建Vue实例
new Vue({
el:'#demo', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。
data:{ //data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象。
name:'atguigu',
address:'北京'
}
})
script>
body>
DOCTYPE html>
<body>
<div id="root">
<h1>插值语法h1>
<h3>你好,{{name}}h3>
<hr/>
<h1>指令语法h1>
<a v-bind:href="school.url.toUpperCase()" x="hello">点我去{{school.name}}学习1a>
<a :href="school.url" x="hello">点我去{{school.name}}学习2a>
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
name:'jack',
school:{
name:'尚硅谷',
url:'http://www.atguigu.com',
}
}
})
script>
DOCTYPE html>
<body>
<div id="root">
单向数据绑定:<input type="text" :value="name"><br/>
双向数据绑定:<input type="text" v-model="name"><br/>
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
name:'尚硅谷'
}
})
script>
DOCTYPE html>
<body>
<div id="root">
<h1>你好,{{name}}h1>
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//el的两种写法
/* const v = new Vue({
//el:'#root', //第一种写法
data:{
name:'尚硅谷'
}
})
console.log(v)
v.$mount('#root') //第二种写法 */
//data的两种写法
new Vue({
el:'#root',
//data的第一种写法:对象式
/* data:{
name:'尚硅谷'
} */
//data的第二种写法:函数式
data(){
console.log('@@@',this) //此处的this是Vue实例对象
return{
name:'尚硅谷'
}
}
})
script>
DOCTYPE html>
<body>
<div id="root">
<h1>学校名称:{{name}}h1>
<h1>学校地址:{{address}}h1>
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷',
address:'北京',
}
})
console.log(vm)
script>
<body>
<script type="text/javascript" >
let number = 18
let person = {
name:'张三',
sex:'男',
}
Object.defineProperty(person,'age',{
// value:18,
// enumerable:true, //控制属性是否可以枚举,默认值是false
// writable:true, //控制属性是否可以被修改,默认值是false
// configurable:true //控制属性是否可以被删除,默认值是false
// number 和 person.age 关联上
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get(){
console.log('有人读取age属性了')
return number
},
//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
set(value){
console.log('有人修改了age属性,且值是',value)
number = value
}
})
// console.log(Object.keys(person))
script>
DOCTYPE html>
<script type="text/javascript" >
let obj = {x:100}
let obj2 = {y:200}
Object.defineProperty(obj2,'x',{
get(){
return obj.x
},
set(value){
obj.x = value
}
})
script>
<body>
<div id="root">
<h2>学校名称:{{name}}h2>
<h2>学校地址:{{address}}h2>
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷',
address:'宏福科技园'
}
})
script>
<body>
<div id="root">
<h2>欢迎来到{{name}}学习h2>
<button @click="showInfo1">点我提示信息1(不传参)button>
<button @click="showInfo2($event,66)">点我提示信息2(传参)button>
div>
body>
<body>
<div id="root">
<h2>欢迎来到{{name}}学习h2>
<a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息a>
<div class="demo1" @click="showInfo">
<button @click.stop="showInfo">点我提示信息button>
div>
<button @click.once="showInfo">点我提示信息button>
<div class="box1" @click.capture="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
div>
div>
<div class="demo1" @click.self="showInfo">
<button @click="showInfo">点我提示信息button>
div>
<ul @wheel.passive="demo" class="list">
<li>1li>
<li>2li>
<li>3li>
<li>4li>
ul>
div>
body>
<body>
<div id="root">
<h2>欢迎来到{{name}}学习h2>
<input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo">
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
Vue.config.keyCodes.huiche = 13 //定义了一个别名按键
new Vue({
el:'#root',
data:{
name:'尚硅谷'
},
methods: {
showInfo(e){
// console.log(e.key,e.keyCode)
console.log(e.target.value)
}
},
})
script>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"> <br/><br/>
名:<input type="text" v-model="lastName"> <br/><br/>
全名:<span>{{firstName}}-{{lastName}}span>
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
}
})
script>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"> <br/><br/>
名:<input type="text" v-model="lastName"> <br/><br/>
全名:<span>{{fullName()}}span>
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
// data只要变了,vue模板就会重新刷新
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
methods: {
fullName(){
console.log('@---fullName')
return this.firstName + '-' + this.lastName
}
},
})
script>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"> <br/><br/>
名:<input type="text" v-model="lastName"> <br/><br/>
全名:<span>{{fullName}}span> <br/><br/>
全名:<span>{{fullName1}}span> <br/><br/>
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
computed:{
fullName:{
//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
get(){
// console.log(this) //此处的this是vm
return this.firstName + '-' + this.lastName;
},
//set什么时候调用? 当fullName被修改时。
set(value){
const arr = value.split('-');
this.firstName = arr[0];
this.lastName = arr[1];
}
},
//简写
fullName1(){
return this.firstName + '-' + this.lastName;
}
}
})
script>
<body>
<div id="root">
<h2>今天天气很{{info}}h2>
<button @click="isHot = !isHot">切换天气button>
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el:'#root',
data() {
return {
isHot:true,
info: '',
numbers: { a: { b: 'bb' } }
}
},
watch:{
isHot:{
immediate:true, //初始化时让handler调用一下
deep:true, // 监视多级结构中所有属性的变化
//handler什么时候调用?当isHot发生改变时。
handler(newValue,oldValue){
this.info = this.isHot ? '炎热' : '凉爽';
}
},
//简写
/* isHot(newValue,oldValue){
this.info = this.isHot ? '炎热' : '凉爽';
} */
// 监视多级结构中某个属性的变化
'numbers.a.b':{
handler(){
console.log('numbers.a.b 被改变了')
}
}
}
})
/* vm.$watch('isHot',{
immediate:true, //初始化时让handler调用一下
//handler什么时候调用?当isHot发生改变时。
handler(newValue,oldValue){
this.info = this.isHot ? '炎热' : '凉爽';
}
}) */
script>
<body>
<div id="root">
<div class="basic" :class="mood" @click="changeMood">{{name}}div> <br/><br/>
<div class="basic" :class="classArr">{{name}}div> <br/><br/>
<div class="basic" :class="classObj">{{name}}div> <br/><br/>
<div class="basic" :style="styleObj">{{name}}div> <br/><br/>
<div class="basic" :style="styleArr">{{name}}div>
div>
body>
<body>
<div id="root">
<h2>当前的n值是:{{n}}h2>
<button @click="n++">点我n+1button>
<template v-if="n === 1">
<h2>你好h2>
<h2>尚硅谷h2>
<h2>北京h2>
template>
div>
body>
<body>
<div id="root">
<h2>(遍历数组)h2>
<ul>
<li v-for="(p,index) of persons" :key="index">
{{p.name}}-{{p.age}}
li>
ul>
<h2>(遍历对象)h2>
<ul>
<li v-for="(value,k) of car" :key="k">
{{k}}-{{value}}
li>
ul>
<h2>遍历字符串(用得少)h2>
<ul>
<li v-for="(char,index) of str" :key="index">
{{char}}-{{index}}
li>
ul>
<h2>遍历指定次数(用得少)h2>
<ul>
<li v-for="(number,index) of 5" :key="index">
{{index}}-{{number}}
li>
ul>
div>
<body>
watch:{
keyWord:{
immediate:true,
handler(val){
this.filPerons = this.persons.filter((p)=> p.name.indexOf(val) !== -1)
}
}
}
or
computed:{
filPerons(){
return this.persons.filter((p)=> p.name.indexOf(this.keyWord) !== -1)
}
}
Vue监视数据的原理:
1. vue会监视data中所有层次的数据。
2. 如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1).对象中后追加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value) 或
vm.$set(target,propertyName/index,value)
3. 如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1).调用原生对应的方法对数组进行更新。
(2).重新解析模板,进而更新页面。
4.在Vue修改数组中的某个元素一定要用如下方法:
1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
2.Vue.set() 或 vm.$set()
特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!
收集表单数据:
若:,则v-model收集的是value值,用户输入的就是value值。
若:,则v-model收集的是value值,且要给标签配置value值。
若:
1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
2.配置input的value属性:
(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
(2)v-model的初始值是数组,那么收集的的就是value组成的数组
备注:v-model的三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
<body>
<div id="root">
<h3>现在是:{{time | timeFormater}}h3>
<h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}h3>
<h3 :x="msg | mySlice">尚硅谷h3>
div>
body>
<script type="text/javascript">
Vue.config.productionTip = false
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
new Vue({
el:'#root',
data:{
time:1621561377603, //时间戳
msg:'你好,尚硅谷'
},
//局部过滤器
filters:{
timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
// console.log('@',value)
return dayjs(value).format(str)
}
}
})
script>
学过的指令:
v-bind : 单向绑定解析表达式, 可简写为 :xxx
v-model : 双向数据绑定
v-for : 遍历数组/对象/字符串
v-on : 绑定事件监听, 可简写为@
v-if : 条件渲染(动态控制节点是否存存在)
v-else : 条件渲染(动态控制节点是否存存在)
v-show : 条件渲染 (动态控制节点是否展示)
v-text指令:
1.作用:向其所在的节点中渲染文本内容。
2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
v-html指令:
1.作用:向指定节点中渲染包含html结构的内容。
2.与插值语法的区别:
(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
(2).v-html可以识别html结构。
3.严重注意:v-html有安全性问题!!!!
(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
v-cloak指令(没有值):
1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
v-once指令:
1.v-once所在节点在初次动态渲染后,就视为静态内容了。
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
v-pre指令:
1.跳过其所在节点的编译过程。
2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
自定义指令总结:
一、定义语法:
(1).局部指令:
new Vue({
directives:{指令名:配置对象} 或 directives{指令名:回调函数}
})
(2).全局指令:
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数)
二、配置对象中常用的3个回调:
(1).bind:指令与元素成功绑定时调用。
(2).inserted:指令所在元素被插入页面时调用。
(3).update:指令所在模板结构被重新解析时调用。
三、备注:
1.指令定义时不加v-,但使用时要加v-;
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
生命周期:
1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
4.生命周期函数中的this指向是vm 或 组件实例对象。
常用的生命周期钩子:
1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。
关于销毁Vue实例
1.销毁后借助Vue开发者工具看不到任何信息。
2.销毁后自定义事件会失效,但原生DOM事件依然有效。
3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
Vue中使用组件的三大步骤:
一、定义组件(创建组件)
使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;
区别如下:
1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
备注:使用template可以配置组件结构。
二、注册组件
1.局部注册:靠new Vue的时候传入components选项
2.全局注册:靠Vue.component('组件名',组件)
三、使用组件(写组件标签):
几个注意点:
1.关于组件名:
一个单词组成:
第一种写法(首字母小写):school
第二种写法(首字母大写):School
多个单词组成:
第一种写法(kebab-case命名):my-school
第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
备注:
(1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
(2).可以使用name配置项指定组件在开发者工具中呈现的名字。
2.关于组件标签:
第一种写法:
第二种写法:
备注:不用使用脚手架时, 会导致后续组件不能渲染。
3.一个简写方式:
const school = Vue.extend(options) 可简写为:const school = options
关于VueComponent:
1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
2.我们只需要写 或 ,Vue解析时会帮我们创建school组件的实例对象,
即Vue帮我们执行的:new VueComponent(options)。
3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
4.关于this指向:
(1).组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
(2).new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
Vue的实例对象,以后简称vm。
内置关系:
1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
. vue-cil 的目录结构
|-- App.vue
|-- assets
| `-- logo.png
|-- components
| |-- School.vue
| `-- Student.vue
`-- main.js
/* 该文件是整个项目的入口文件 */
import Vue from 'vue' //引入Vue
import App from './App.vue' //引入App组件,它是所有组件的父组件
Vue.config.productionTip = false; //关闭vue的生产提示
/* 关于不同版本的Vue:
1.vue.js与vue.runtime.xxx.js的区别:
(1).vue.js是完整版的Vue,包含:核心功能+模板解析器。
(2).vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。
2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用
render函数接收到的createElement函数去指定具体内容。
*/
//创建Vue实例对象---vm
new Vue({
el:'#app',
//render函数完成了这个功能:将App组件放入容器中
render: h => h(App),
// render:q=> q('h1','你好啊')
// template:`你好啊
`,
// components:{App},
})
<template>
<div>
<img src="./assets/logo.png" alt="logo">
<School>School>
<Student>Student>
div>
template>
<script>
//引入组件
import School from './components/School'
import Student from './components/Student'
export default {
name:'App',
components:{
School,
Student
}
}
script>
<template>
<div>
<h1 v-text="msg" ref="title">h1>
<button ref="btn" @click="showDOM">点我输出上方的DOM元素button>
<School ref="sch"/>
div>
template>
<script>
//引入School组件
import School from './components/School'
export default {
name:'App',
components:{School},
data() {
return {
msg:'欢迎学习Vue!'
}
},
methods: {
showDOM(){
console.log(this.$refs.title) //真实DOM元素
console.log(this.$refs.btn) //真实DOM元素
console.log(this.$refs.sch) //School组件的实例对象(vc)
}
},
}
script>
//简单声明接收
// props:['name','age','sex']
//接收的同时对数据进行类型限制
/* props:{
name:String,
age:Number,
sex:String
} */
//接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
props:{
name:{
type:String, //name的类型是字符串
required:true, //name是必要的
},
age:{
type:Number,
default:99 //默认值
},
sex:{
type:String,
required:true
}
}
// mixin.js
export const hunhe = {
methods: {
showName(){
alert(this.name)
}
},
mounted() {
console.log('你好啊!')
},
}
export const hunhe2 = {
data() {
return {
x:100,
y:200
}
},
}
<template>
<div>
<h2 @click="showName">学生姓名:{{name}}h2>
<h2>学生性别:{{sex}}h2>
div>
template>
<script>
import {hunhe,hunhe2} from '../mixin'
export default {
name:'Student',
data() {
return {
name:'张三',
sex:'男'
}
},
mixins:[hunhe,hunhe2]
}
script>
// main.js
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件
import plugins from './plugins'
//关闭Vue的生产提示
Vue.config.productionTip = false
//应用(使用)插件
Vue.use(plugins,1,2,3)
//创建vm
new Vue({
el:'#app',
render: h => h(App)
})
// plugins.js
export default {
install(Vue,x,y,z){
console.log(x,y,z)
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
//定义全局指令
Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
})
//定义混入
Vue.mixin({
data() {
return {
x:100,
y:200
}
},
})
//给Vue原型上添加一个方法(vm和vc就都能用了)
Vue.prototype.hello = ()=>{alert('你好啊')}
}
}
// 父组件
<template>
<div class="app">
<h1>{{msg}},学生姓名是:{{studentName}}h1>
<School :getSchoolName="getSchoolName"/>
<Student ref="student" @click.native="show"/>
div>
template>
<script>
import Student from './components/Student'
import School from './components/School'
export default {
name:'App',
components:{School,Student},
data() {
return {
msg:'你好啊!',
studentName:''
}
},
mounted() {
this.$refs.student.$on('atguigu',this.getStudentName) // 另一种绑定方式,绑定自定义事件
// this.$refs.student.$once('atguigu',this.getStudentName) //绑定自定义事件(一次性)
},
}
script>
// 子组件
<script>
export default {
methods: {
sendStudentlName(){
//触发Student组件实例身上的atguigu事件
this.$emit('atguigu',this.name,666,888,900)
// this.$emit('demo')
// this.$emit('click')
},
unbind(){
this.$off('atguigu') //解绑一个自定义事件
// this.$off(['atguigu','demo']) //解绑多个自定义事件
// this.$off() //解绑所有的自定义事件
},
death(){
this.$destroy() //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效。
}
}
}
script>
// main.js
import Vue from 'vue'
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
// 总线bus挂载到Vue上,也会挂载到cm上,所以可以用this.$bus.$emit and this.$bus.$on event
/*
this.$bus.$emit('hello',this.name)
this.$bus.$on('hello',(data)=>{
console.log('我是School组件,收到了数据',data)
})
也可以引入第三方 'pubsub-js'
*/
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线
},
})
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏button>
<transition name="hello" appear>
<h1 v-show="isShow">你好啊!h1>
transition>
div>
template>
<script>
// transition + name + style(hello-enter-active and hello-leave-active)
export default {
name:'Test',
data() {
return { isShow:true }
},
}
script>
<style scoped>
h1{ background-color: orange; }
.hello-enter-active{ animation: atguigu 0.5s linear; }
.hello-leave-active{ animation: atguigu 0.5s linear reverse; }
@keyframes atguigu {
from{ transform: translateX(-100%); }
to{ transform: translateX(0px); }
}
style>
// 组件中引入 axios
import axios from 'axios'
export default {
name:'App',
methods: {
getStudents(){
axios.get('http://localhost:8080/students').then(
response => {
console.log('请求成功了',response.data)
},
error => {
console.log('请求失败了',error.message)
}
)
},
getCars(){
axios.get('http://localhost:8080/demo/cars').then(
response => {
console.log('请求成功了',response.data)
},
error => {
console.log('请求失败了',error.message)
}
)
}
},
}
<template>
<div class="category">
<h3>{{title}}分类h3>
<slot>我是一些默认值,当使用者没有传递具体结构时,这句就会出现slot>
div>
template>
<template>
<div class="container">
<Category title="美食" >
// 塞到默认插槽中
<img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
Category>
<Category title="游戏" >
<ul><li v-for="(g,index) in games" :key="index">{{g}}li>ul>
Category>
<Category title="电影">
<video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4">video>
Category>
div>
template>
<template>
<div class="category">
<h3>{{title}}分类h3>
<slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现1slot>
<slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现2slot>
div>
template>
<template>
<div class="container">
<Category title="美食" >
<img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
<a slot="footer" href="http://www.atguigu.com">更多美食a>
Category>
<Category title="游戏" >
<ul slot="center">
<li v-for="(g,index) in games" :key="index">{{g}}li>
ul>
<div class="foot" slot="footer">
<a href="http://www.atguigu.com">单机游戏a>
<a href="http://www.atguigu.com">网络游戏a>
div>
Category>
// template 会少包裹层
<Category title="电影">
<video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4">video>
<template v-slot:footer>
<div class="foot">
<a href="http://www.atguigu.com">经典a>
<a href="http://www.atguigu.com">热门a>
<a href="http://www.atguigu.com">推荐a>
div>
template>
Category>
div>
template>
<template>
<div class="category">
<h3>{{title}}分类h3>
<slot :games="games" msg="hello">我是默认的一些内容slot>
div>
template>
<template>
<div class="container">
<Category title="游戏">
<template scope="atguigu">
<ul>
<li v-for="(g,index) in atguigu.games" :key="index">{{g}}li>
ul>
template>
Category>
<Category title="游戏">
<template scope="{games}">
<ol>
<li style="color:red" v-for="(g,index) in games" :key="index">{{g}}li>
ol>
template>
Category>
<Category title="游戏">
<template slot-scope="{games}">
<h4 v-for="(g,index) in games" :key="index">{{g}}h4>
template>
Category>
div>
template>
// store - index.js
//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
// 应用Vuex插件
Vue.use(Vuex)
//创建并暴露store
export default new Vuex.Store({
state:{
counter:1000
},
mutations:{
increment(state) {
state.counter++;
}
},
actions:{},
getters:{},
modules:{}
})
// main.js
import Vue from 'vue'
import App from './App.vue'
//引入store
import store from './store'
//创建vm
new Vue({
el:'#app',
render: h => h(App),
store
})
// 组件
<script>
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
export default {
name:'Count',
data() {
return {
n:1, //用户选择的数字
}
},
computed:{
...mapState(['sum','school','subject']),
...mapGetters(['bigSum'])
},
methods: {
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
...mapMutations({increment:'funName1',decrement:'funName2'}),
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)
// ...mapMutations(['funName1','funName2']),
add() {
console.log(this.$store.state.counter); // 获取store 的value
this.$store.commit('increment');
},
//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
...mapActions({incrementOdd:'funName3',incrementWait:'funName4'})
//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(数组写法)
// ...mapActions(['funName3','funName4'])
}
}
script>
// store - index.js
//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
// 两个模块的配置文件
import countOptions from './count'
import personOptions from './person'
//应用Vuex插件
Vue.use(Vuex)
//创建并暴露store
export default new Vuex.Store({
modules:{
countAbout:countOptions,
personAbout:personOptions
}
})
<script>
export default {
name:'Person',
computed:{
personList(){
return this.$store.state.personAbout.personList
},
sum(){
return this.$store.state.countAbout.sum
},
firstPersonName(){
return this.$store.getters['personAbout/firstPersonName']
}
},
methods: {
add(){
const personObj = { name:this.name };
this.$store.commit('personAbout/ADD_PERSON',personObj);
},
addWang(){
const personObj = {id:nanoid(),name:this.name};
this.$store.dispatch('personAbout/addPersonWang',personObj);
},
addPersonServer(){
this.$store.dispatch('personAbout/addPersonServer')
}
},
}
script>
// router.js 专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
// 创建并暴露一个路由器
export default new VueRouter({
routes:[
{
name: 'about',
path:'/about',
component: () => import('../components/About')
},
{
name: 'home',
path:'/home',
component: () => import(/* webpackChunkName: "group-user" */ '../components/Home'),
children:[
{
path:'news',
component: () => import(/* webpackChunkName: "group-user" */ '../components/News'),
},
{
name: 'message',
path:'message',
component: () => import(/* webpackChunkName: "group-user" */ '../components/Message'),
},
{
name:'xiangqing',
path:'detail/:id/:title',
component: () => import(/* webpackChunkName: "group-user" */ '../components/Detail'),
}
]
}
]
})
// main.js
import Vue from 'vue'
import App from './App.vue'
//引入VueRouter
import VueRouter from 'vue-router'
//引入路由器
import router from './router'
//应用插件
Vue.use(VueRouter)
//创建vm
new Vue({
el:'#app',
render: h => h(App),
router:router
})
前: () => import('../components/About')
后: () => import(/* webpackChunkName: "group-user" */ '../components/Message'),
// 两者的打包方式不同,前者单独一个js文件,后者会将 "group-user" 系列打包到 group-user.xxx,js中
<template>
<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}}router-link>
<router-link :to="{
path:'/home/message/detail',
query:{
id:m.id,
title:m.title
}
}">{{m.title}}router-link>
<router-view>router-view>
div>
template>
// 目标路由组件
<template>
<ul>
<li>消息编号:{{$route.query.id}}li>
<li>消息标题:{{$route.query.title}}li>
ul>
template>
<template>
<div>
<router-link :to="{
name:'message',
query:{
id:m.id,
title:m.title
}
}"> {{m.title}} router-link>
<router-view>router-view>
div>
template>
<template>
<div>
<router-link :to="{
name:'xiangqing',
params:{
id:m.id,
title:m.title
}
}"> {{m.title}} router-link>
<hr>
<router-view>router-view>
div>
template>
// main.js 专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
//创建并暴露一个路由器
export default new VueRouter({
routes:[
{
path:'/home',
component: () => import('../pages/Home'),
children:[
{
path:'message',
component:Message,
children:[
{
name:'xiangqing',
path:'detail',
component:Detail,
//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件。
// props:{a:1,b:'hello'}
//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件。
// props:true
//props的第三种写法,值为函数
props($route){
return {
id:$route.query.id,
title:$route.query.title,
a:1,
b:'hello'
}
}
}
]
}
]
}
]
})
<template>
<ul>
<li>消息编号:{{id}}li>
<li>消息标题:{{title}}li>
ul>
template>
<script>
export default {
name:'Detail',
props:['id','title'],
computed: {
// id(){
// return this.$route.query.id
// },
// title(){
// return this.$route.query.title
// },
},
}
script>
<router-link replace class="list-group-item" active-class="active" to="/home/news">Newsrouter-link>
<router-link :replace="true" class="list-group-item" active-class="active" to="/home/news">Newsrouter-link>
methods: {
back(){
this.$router.back()
// console.log(this.$router)
},
forward(){
this.$router.forward()
},
test(){
this.$router.go(3)
},
pushShow(m){
this.$router.push({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
},
replaceShow(m){
this.$router.replace({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
}
}
<template>
<div>
<h2>Home组件内容h2>
<div>
<router-link class="list-group-item" active-class="active" to="/home/news">Newsrouter-link>
<router-link class="list-group-item" active-class="active" to="/home/message">Messagerouter-link>
<keep-alive include="News">
<router-view>router-view>
keep-alive>
div>
div>
template>
<script>
export default {
name:'News',
activated() {
console.log('News组件被激活了')
this.timer = setInterval(() => {
console.log('@')
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
},16)
},
deactivated() {
console.log('News组件失活了')
clearInterval(this.timer)
},
}
script>
// main.js 专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
//创建并暴露一个路由器
const router = new VueRouter({
routes:[
{
name:'guanyu',
path:'/about',
component: () => import('../pages/About'),
meta:{title:'关于'},
beforeEnter: (to, from, next) => {
console.log('独享路由守卫',to,from)
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem('school')==='atguigu'){
next()
}else{
alert('学校名不对,无权限查看!')
}
}else{
next()
}
}
}
]
})
//全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
console.log('前置路由守卫',to,from)
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem('school')==='atguigu'){
next()
}else{
alert('学校名不对,无权限查看!')
}
}else{
next()
}
})
//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
console.log('后置路由守卫',to,from)
document.title = to.meta.title || '硅谷系统'
})
export default router;
<template>
<h2>我是About的内容h2>
template>
<script>
export default {
name:'About',
//通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
console.log('About--beforeRouteEnter',to,from)
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem('school')==='atguigu'){
next()
}else{
alert('学校名不对,无权限查看!')
}
}else{
next()
}
},
//通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
console.log('About--beforeRouteLeave',to,from)
next()
}
}
script>