本文已参与 [新人创作礼] 活动 , 一起启动掘金创作之路!
认知Vue
三大框架(vue、react、angular)
Vue主要做什么
- 不需要操作DOM
- 单页面应用页项目
- 采用类似React语法,用于 微信小程序/MpVue
特点
- 数据驱动视图
- MVVM 双向绑定
- 通过 指令 增强 html功能
- 组件化 复用代码
- 开发者只需关注数据
API
VueAPI:cn.vuejs.org/v2/api/
Vue中文社区:www.vue-js.com/
安装
安装应用的方式向引入 js代码 一样即可
-
下载 Vue.js 库,本地引入
-
在线 CDN 引入
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
Vue应用
步骤:
- body中,设置Vue管理的视图====
- 引入vue.js
- 实例化 Vue对象new Vue();
- 设置Vue实例的选项:如el、data... new Vue({选项:值});
- 在 ==== 中通过{{ }}使用data中的数据 (插值表达式)
<body>
<!-- 1. 提供容器 -->
<div id="app">
<p>{{str}}</p>
</div>
<!-- 2. 引入vue -->
<script src="vue.js"></script>
<script>
// 3. 模拟数据
new Vue({
// 配置vue选项
// 选择器选择容器
el: '#app',
// 设置数据
data: {
str: '测试对象'
}
})
</script>
</body>
Vue生命周期
Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂在DOM、渲染-更新-渲染、卸载等过程,这些过程会运行一些叫做 生命周期钩子 的函数,提供了在不同生命周期中需要实现的功能!
首次接触Vue不建议看该章节
Vue生命周期函数分别有:
- 创建期
beforeCreatecreatedbeforeMountmounted
- 运行期
beforeUpdateupdated
- 销毁期
beforeDestroydestroyed
Vue生命周期完整图:
创建期
Vue实例创建期的钩子函数,分别在不同创建执行的钩子函数
| 实例时间线 | 钩子函数 | 说明 |
|---|---|---|
| T1 数据/方法未加载 | beforeCreate | Vue实例 初始化 后执行 |
| T2 数据/方法刚加载 | created | Vue实例 数据/方法 加载后执行 |
| T3 模板刚好编译完 | beforeMount | Vue实例 HTML模板编译后执行 |
| T4 页面渲染渲染完 | mounted | DOM模型渲染完后执行 |
示例:
<div id="app">
<p>{{msg}}</p>
</div>
....
<script>
new Vue({
el: "#app",
data: {
msg: "Hello world",
},
methods: {
say() {
console.log("load...say()")
}
},
// 生命周期测试
beforeCreate() {
// Vue实例初始化后执行(没有数据和方法
console.log("beforeCreate() => ", this.msg)
// 方法编译时会报错
/* 控制台结果
beforeCreate() => undefined
* */
},
created() {
// Vue实例加载数据和方法后执行
console.log("created() => ", this.msg, this.say())
/* 控制台结果
load...say()
created() => Hello world undefined
* */
},
beforeMount() {
// 模板编译后执行(此时页面为渲染
console.log("beforeMount() => ",
"html:" + document.querySelector("p").innerHTML,
"text:" + document.querySelector("p").innerText
)
/* 控制台结果
beforeMount() => html:{{msg}} text:{{msg}}
* */
},
mounted() {
// DOM模型渲染完后执行
console.log("mounted() => ",
"html:" + document.querySelector("p").innerHTML,
"text:" + document.querySelector("p").innerText
)
/* 控制台结果
mounted() => html:Hello world text:Hello world
* */
}
});
</script>
运行期
Vue实例在页面渲染后的期间为运行期间,当中触发钩子函数的有 数据变化
| 实例时间线 | 钩子函数 | 说明 |
|---|---|---|
| T4+ 数据更变/页面渲染前 | beforeUpdate | 实例中的数据被 修改前执行 |
| T5+ 数据更变/页面渲染前 | updated | 实例中的数据被 修改后执行 |
示例:
<div id="app">
<p>{{count}}</p>
<button @click="add">add</button>
</div>
....
<script>
new Vue({
el: "#app",
data: {
count: 0
},
methods:{
add() {
this.count++;
}
},
beforeUpdate() {
// 实例中的数据被修改前执行
console.log("beforeUpdate() => ",
"this: "+this.count,
"html: "+document.querySelector("p").innerHTML,
"text: "+document.querySelector("p").innerText
)
/* 控制台数据(点击3次)
beforeUpdate() => this: 1 html: 0 text: 0
beforeUpdate() => this: 2 html: 1 text: 1
beforeUpdate() => this: 3 html: 2 text: 2
*/
},
updated() {
// 实例中的数据被修改后执行
// 实例中的数据被修改前执行
console.log("updated() => ",
"this: "+this.count,
"html: "+document.querySelector("p").innerHTML,
"text: "+document.querySelector("p").innerText
)
/* 控制台数据(点击3次)
updated() => this: 1 html: 1 text: 1
updated() => this: 2 html: 2 text: 2
updated() => this: 3 html: 3 text: 3
*/
}
});
</script>
销毁期
Vue实例和Vue的组件生命周期一样,也有相同的功能以及选项,因此在测试应用也如此,在这一销毁期当中有两个钩子函数分别是
| 实例时间线 | 钩子函数 | 说明 |
|---|---|---|
| T(end-1) 组件销毁前 | beforeDestroy | 实例/组件 被销毁前执行 |
| T end 组件销毁后 | destroyed | 实例/组件 被销毁后执行 |
示例:
示例运用 v-if指令使 组件Element节点删除 的方式,对销毁函数产生调用
<div id="app">
<button @click="toggle">切换</button>
<son v-if="flag"></son>
</div>
....
<template id="son">
<div>
<p>我是组件</p>
</div>
</template>
<script>
Vue.component("son", {
template: "#son",
data() {
return {
msg: "hello"
}
},
methods: {
say() {
console.log("Say()")
}
},
beforeDestroy() {
console.log("beforeDestroy() => 组件销毁",
this.msg, this.say()
)
},
destroyed() {
// 数据/方法 在组件销毁后应用 报红
console.log("destroyed() => 组件销毁"
// this.msg, this.say()
)
}
})
new Vue({
el: "#app",
data: {
flag: true
},
methods: {
toggle() {
this.flag = !this.flag;
}
}
})
</script>
Vue选项
选项都是可以直接写在vue实例下的,被分为了几类:
- 数据选项
- DOM选项
- 生命周期钩子 选项
- 资源选项
- 组合选项
- 其他选项
由于选项众多,不能一一举例,更详细了解自行API
数据选项
data 数据
**作用:**将数据响应式同步显示视图
类型:==Object | Function==
关键字: data
数据可在指定的el容器进行数据访问。如:数据name , 视图中 {{name}} 访问数据
在容器中数据一旦发生改变,视图中的数据也会跟随改变
示例
<div id="app">
<p>{{count}}</p>
<p>{{msg}}</p>
<p>{{list}}</p>
</div>
...
<script>
let vm = new Vue({
el: '#app',
data:{
count: 100,
msg:"张三最帅!",
list: [1,2,3,4]
}
})
vm.count = 300;
console.log(vm);
console.log("=====");
console.log(vm.count);
console.log(vm.msg);
console.log(vm.list);
console.log("=====");
console.log(vm._data);
</script>
<!-- 浏览器结果
300
张三最帅!
[ 1, 2, 3, 4 ]
-->
<!-- 控制台结果 (vue太长了)
Vue {...}
=====
300
张三最帅!
(4) [1, 2, 3, 4, __ob__: Observer]0: 11: 22: 33: 4length: 4__ob__: Observer {value: Array(4), dep: Dep, vmCount: 0}[[Prototype]]: Array
=====
{__ob__: Observer}
-->
props传递
**作用:**接受父组件传值
类型:==Array | Object==
关键字: props
示例:跳转示例
methods 方法
**作用:**执行方法(函数)的操作
类型:=={ [key: string]: Function }==
**值:**method对象
关键字: methods
- 可通过 实例对象 访问对象内的方法
- 方法中 访问本身 属性/方法 需要 自身实例对象/this本身对象
- method函数不建议使用箭头函数来定义,因 箭头函数会绑定上下级关系,在本对象的其他方法通过 自身实例对象/this本身对象 进行访问时,可能访问不到
书写形式:
methods:{
<方法名1>:function(){...}
[,<方法名2>() {...}]
}
示例
<body>
<div id="app">
<!-- 也可以直接调用 -->
<!-- <p>{{fn1()}}</p> -->
<p>{{count}}</p>
<button v-on:click="fn1()">count++ (函数1)</button><br/>
<button v-on:click="fn2">count++ (函数2)</button>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data:{
count:100
},
methods:{
fn1:function(){
console.log("调用了function()函数1");
// this对象本身的属性
vm.count++;
},
fn2() {
// vm当前实例的属性
console.log("调用了function()函数2");
this.count++;
}
}
})
// 实例对象调用
// vm.fn1();
// vm.fn2();
</script>
</body>
computed 计算属性
**作用:**为属性值做数据处理,以防 插值表达式 应用逻辑复杂
类型:=={ [key: string]: Function | { get: Function, set: Function } }==
**API:**cn.vuejs.org/v2/guide/co…
关键字: computed
步骤:
-
在 data 定义好 数据变量
-
定义 计算属性 的方法
computed:{ <计算属性名>: function () { return ...; } } -
使用计算属性 (使用方式与 插值表达式 一样 =={{<计算属性名>}}==
computed 与 methods 的区别:
- computed直接通过 计算属性名 调用 ; 而 methods方法 采用 方法名() 调用
- computed绑定的是 data中的数据 ; 而 methods方法 无论执行与否 都会重新计算
示例:
<p>{{msg}}</p>
<p>{{reversMsg}}</p>
// hello!
// !olleh
...
<script>
new Vue({
el:"...",
data:{
msg:"hello!"
},
computed :{
reversMsg: function () {
// split() 将字符串对指定对象进行分割
// reverse() 将数组反转
// join() 将数组中对象拼接返回字符串
return this.msg.split('').reverse().join('');
}
}
});
</script>
watch 数据监听
作用: 监听指定 数据变化时 触发的函数
类型:=={ [key: string]: string | Function | Object | Array }==
关键字: watch
步骤:
-
在 data 定义好 数据变量
-
设置监听 属性
watch: { <属性名>(newV, oldV) {...} [,<dat属性名2>(newV, oldV){...}...] }
computed 与 watch 的区别:
- computed 必须有返回值 ,由于异步请求缘故,返回值可能是无效值
- watch 无需返回值,不用管优先顺序的问题
典型事例:用户列表 (自行测试)
DOM选项
el 选择器
**作用:**指定容器vue实例管理的html视图
类型:==string | Element==
Element值: id选择器/class选择器/dom对象
关键字: el
示例:
<body>
<!-- 提供容器 -->
<div id="app1">
<p>{{str}}</p>
</div>
<div class="app2">
<p>{{str}}</p>
</div>
<div name="app3">
<p>{{str}}</p>
</div>
<script src="vue.js"></script>
<script>
// id选择
new Vue({
el: '#app1',
data: {
str: '测试对象1'
}
})
// class选择
new Vue({
el: '.app2',
data: {
str: '测试对象2'
}
})
// dom对象选择
new Vue({
el: document.getElementsByName("app3")[0],
data: {
str: '测试对象3'
}
})
</script>
</body>
<!-- 浏览器 结果
测试对象1
测试对象2
测试对象3
-->
template 模板
作用: 组件应用的模板将会替换挂载指定组件
类型:==String==
关键字:template
示例:跳转示例
**注意:**一个模板最外层只能有一个根元素
render 渲染
**作用:**将预先注册好的组件,可通过 render()方法直接渲染
类型:==(createElement: () => VNode) => VNode==
关键字:render
标签渲染 与 render()方法渲染 的区别:
- 标签渲染,不会覆盖Vue实例控制区域
- render方法渲染,会覆盖Vue实例控制区域
- 必选,createElement:用于return虚拟DOM
- 可选,context:接收其他组件传递的数据
createElement参数
createElement参数是 用于创建 VNode节点 ,同时也是方法中的第一个参数
createElement创建方式
new Vue({
el: "#app",
render: (h) =>{
return h("h6", {class: "abc"}, "我是h6")
}
})
渲染结果
<div id="app">
<h6 class="abc">我是h6</h6>
</div>
上面例的 h 是 createElement 的缩写,其中有三个形参
| 参数 | 类型 | 说明 |
|---|---|---|
| 1 必选 | String | 通过字符串解析HTML标签进行创建 |
| 2 可选 | Object | 为虚拟DOM编写属性参数等 |
| 3 可选 | String | Array | 数组视为:子虚拟DOM节点 字符串视为:标签中的内容 |
添加Vue指令功能以及事件点击详细了解
示例1:
<div id="app">
<!-- 解释:
插槽的作用域 和 组件子父类的作用域 不同,因此传递传递参数的方式也不同
slot-scope : 提供过插槽传递出来的 数据集
:msg : 传递msg数据传递给子组件应用
PS:为了更直观的呈现应用了自定义名称传递
-->
<father>
<son slot-scope="aaa" :msg="aaa.bbb"></son>
</father>
</div>
</body>
...
<template id="father">
<div>
<p>我是父组件</p>
<!-- 为当前插槽传递数据出去 -->
<slot :bbb="say"></slot>
</div>
</template>
<script>
Vue.component("father", {
template: "#father",
data() {
return {
say: "你好我是父组件!"
}
}
})
Vue.component("son", {
// 组件函数化
functional: true,
render: (h, context) => {
// 接收其他组件传递的数据
console.log(context)
return h("h6", {class: "abc"}, context.props.msg)
},
props: ["msg"]
})
new Vue({
el: "#app"
})
</script>
渲染结果
<div id="app">
<div>
<p>我是父组件</p>
<h6 class="abc">你好我是父组件!</h6>
</div>
</div>
资源选项
directives 自定义指令
类型:==Object==
关键字:directives
示例:跳转示例
components 组件
类型:==Object==
关键字:components
示例:跳转示例
filters 过滤器
**作用:**自定义格式化data数据
类型: ==Object==
关键字: filters
**API:**cn.vuejs.org/v2/guide/fi…
步骤:
-
定义过滤器 全局/局部 全局过滤器
Vue.filter(<过滤器名称>, function (value) { return ...; });局部过滤器
filters: { <过滤器名称>: function (value) { return ...; } [, <过滤器名称>: function (value){...}] } -
应用过滤器 (前提该标签在Vue容器范围内
// No.1 插值表达式应用 {{<数据>|<过滤器名称>}} // No.2 v-bind指令应用 <p v-bind:id="<数据>|<过滤器名称>">...</p>
示例:
<div id="app1">
<h2>app1</h2>
<p>{{msg|no1}}</p>
<p>{{msg|no2}}</p>
</div>
<div id="app2">
<h2>app2</h2>
<p>{{msg|no1}}</p>
<p>{{msg|no2}}</p>
</div>
...
<script>
// 全局过滤器 (首字母大写
Vue.filter("no1", function (v) {
return v.charAt(0).toUpperCase()+v.slice(1);
});
new Vue({
el: "#app1",
data: {
msg: "hello"
},
// 局部过滤器 (尾字母大写
filters: {
no2: function (v) {
let len = v.length;
return v.slice(0, len - 2) + v.charAt(len - 1).toUpperCase();
}
}
});
new Vue({
el: "#app2",
data: {
msg: "world"
}
});
</script>
带参串联应用
使用顺序与我们Java方法链式调用方法一样,可以多个过滤器串行使用
// 100元人民币
<p> {{msg|unit('元')|type('人民币')}} </p>
...
<script>
new Vue({
el: "#app",
data: {
msg: 100
},
filters: {
unit: function (val, unit) {
return val + unit;
},
type: function (val, type) {
return val + type;
}
}
});
</script>
日期格式处理
借助第三方插件:momentjs.cn/
CDN:cdn.staticfile.org/moment.js/2…
步骤:
- 引入插件 moment.js
- 创建格式格式化日期过滤器
- 格式化日期操作 ==moment(<日期对象>).format(<日期格式>)==
示例:
// 2022-03-12 18:23:46
<p>{{msg|dateFormat}}</p>
...
<script src="https://cdn.staticfile.org/moment.js/2.24.0/moment.js"></script>
<script>
new Vue({
el: "#app",
data: {
msg: new Date()
},
filters: {
dateFormat: function (v) {
return moment(v).format("YYYY-MM-DD HH:mm:ss");
}
}
});
</script>
Vue组件
**作用:**在不同的组件共同应用时数据会相互干扰,因此要为该组件单独开辟一个单独data的地址
关键字: components(局部使用) / component (全局使用)
组件命名:
- 组件的命名不支持 驼峰命名
- 传递 属性/方法 也不能使用 驼峰命名
- 驼峰命名 的应用替换至短横线分隔命名
步骤:
-
定义 局部/全局 Vue组件
局部 Vue组件 (在components选项中
components:{ <Vue组件名> : { template: <根元素>, data() { return{ <key>:<value> } } } [, <Vue组件名2> : {...}] }全局 Vue组件
Vue.component(<Vue组件名>,{ template: <根元素>, data() { return{ <key>:<value> } } ); -
在 Vue容器中 添加 Vue组件
<Vue组件名></Vue组件名>
模板应用方式
-
Js代码中
let tmp = '<div>...</div>'; ... Vue.component(...,{ template: tmp }) -
script标签中
<script id="info"> <div>...</div> </script> ... Vue.component(...,{ template: "#info" }) -
template标签中
<template id="info"> <div>...</div> </template> ... Vue.component(...,{ template: "#info" })
Vue组件 与 Vue实例 的区别:
- Vue组件 data需要函数返回值。而且只能返回一个对象
- Vue组件 没有 el选项,但有 template选项 代表页面结构(自要一个根元素
- Vue组件之间的数据都是相互独立的,运行的 作用域、数据、逻辑 没有关联
<div id="app">
<h3>组件复用</h3>
<button-count></button-count>
<button-count></button-count>
<button-count></button-count>
<br> <h3>组件共用</h3>
<button @click="count++">按钮 {{count}}</button>
<button @click="count++">按钮 {{count}}</button>
<button @click="count++">按钮 {{count}}</button>
</div>
<script src="vue.js"></script>
<script>
Vue.component('button-count', {
data: function() {
return {count : 0}
},
template:'<button @click="count++">按钮 {{count}}</button>'
});
new Vue({
el: '#app',
data:{
count: 0
}
})
</script>
示例2:
<div id="app">
<component-a></component-a>
<component-b></component-b>
</div>
<script src="vue.js"></script>
<script>
// 全局
Vue.component("component-a",{
template: '<div>\n' +
' <button @click="cut"><</button>\n' +
' <span>{{count}}</span>\n' +
' <button @click="add">></button>\n' +
' </div>',
data() {
return{
count: 0
}
},
methods:{
add() {
console.log("add")
this.count++;
},
cut() {
console.log("cut")
this.count--;
}
}
});
new Vue({
el:"#app",
data:{},
// 局部
components:{
"component-b" : {
template: '<div>\n' +
' <button @click="cut">减</button>\n' +
' <span>{{count}}</span>\n' +
' <button @click="add">加</button>\n' +
' </div>',
data() {
return{
count: 0
}
},
methods:{
add() {
console.log("add")
this.count++;
},
cut() {
console.log("cut")
this.count--;
}
}
}
}
});
</script>
组件嵌套
嵌套情况: (其他方式嵌套不可用
- 全局 套 全局
- 局部 套 全局
示例:
<div id="app">
<h1>全局 套 全局</h1>
<parent-all-a></parent-all-a>
<!--<h1>局部 套 局部</h1>-->
<h1>局部 套 全局</h1>
<parent-part-b></parent-part-b>
</div>
...
<script>
// 全局
Vue.component("child-all-a",{
template:'<p>child-part-a</p>'
});
Vue.component("child-all-b",{
template:'<p>child-part-b</p>'
});
// 全局 套 全局
Vue.component("parent-all-a",{
template:'<div>\n' +
' 全局\n' +
' <child-all-a></child-all-a>\n' +
' <child-all-b></child-all-b>\n' +
' </div>'
})
// 局部
new Vue({
el:"#app",
data:{},
components: {
"child-part-a":{
template:'<p>child-part-a</p>'
},
"child-part-b":{
template:'<p>child-part-b</p>'
},
"parent-part-b":{ // 局部 套 全局
template:'<div>\n' +
' 局部\n' +
' <child-all-a></child-all-a>\n' +
' <child-all-b></child-all-b>\n' +
' </div>'
}
}
});
</script>
组件通信
由于组件之间的数据都是相互独立互不干扰,如果组件之间的数据需要交互情况可应用 props选项 绑定属性传递即可获取
组件之间的通信是根据关系划分为:
- 父组件通信
- 子组件通信
- 同胞组件通信
关键字:props (数据传递) / emit (方法传递)
数据通信
关键字:props
步骤: (应用前提 Vue容器 data 包含有 msg属性
- 创建 Vue组件
- 添加 props选项 增加绑定属性(任意) ==props : [<自定义属性名>]== (数组形式可写多个绑定属性)
- 在引用 Vue组件 的标签 中添加绑定属性 对应的 父组件属性/Vue属性 ==<<组件名> :<绑定属性名>="<父组件属性名>"></<组件名>>==
注意:
- 子组件的 props选项 值是一个数组
- 数组中的值是 绑定子组件上的属性 用于接收父组件的传值
- 子组件的 template选项 可直接使用 绑定好的属性,从而实现获取父组件传递的值
- 子组件 更变绑定的属性值 ,不会对其父组件的 data数据有任何影响
<div id="app">
<child-a :msg="msgParent"></child-a>
<p>父组件msgParent:{{msgParent}}</p>
</div>
...
<script>
Vue.component("child-a",{
template:'<div>\n' +
' <p>子组件 data.count = {{count}}</p>\n' +
' <p>父容器 data.msgParent = {{msg}}</p>\n' +
' <button @click="add">++</button>\n' +
' </div>',
data() {
return{
count : 100
}
},
methods:{
add() {
this.count++;
this.msg++;
}
},
// 绑定 指定的data
props:['msg']
});
new Vue({
el:"#app",
data:{
msgParent : 200
}
})
</script>
方法通信
步骤: (前提父组件已经有方法 且可直观的呈现
-
父组件模板中的子类标签 添加 ==@<自定义名称>: "方法名"== (用于传递方法
<template id="Father"> <div> ... <!-- 传递方法 <自定义名称 parentsay> --> <son @parentsay="say"></son> </div> </template> -
子类添加自定义方法,使用 ==this.$emit(<自定义名称> [, 方法的参数])== (用于回调父类的方法
// 通过 sonFn()进行 调用父类的方法 components: { "son":{ template: "#Son", methods:{ // 自定义方法 调用父类传递的方法 sonFn() { this.$emit("parentsay"); } } } }
传递方法条件:
- 父组件向子组件传递方法 前提需要在父组件模板中的子组件标签添加 传递的关键字
- 子组件应用父组件中的方法 子组件必须创建自定义方法进行调用
<div id="app">
<father></father>
</div>
...
<template id="Father">
<div>
<p>父组件</p>
<button @click="say('父类')">按钮</button>
<!-- 传递方法 <自定义名称 parentsay> -->
<son @parentsay="say"></son>
</div>
</template>
<template id="Son">
<div>
<p>子组件</p>
<button @click="sonFn('子类')">按钮</button>
</div>
</template>
...
<script>
new Vue({
el: "#app",
data: {},
components: {
"father": {
template: "#Father",
components: {
"son":{
template: "#Son",
methods:{
// 自定义方法 调用父类传递的方法
sonFn(type) {
this.$emit("parentsay",type);
}
}
}
},
methods:{
say(type) {
alert(type+": 已经点击啦!")
}
}
}
}
})
</script>
匿名插槽
插槽 是给组件模板添加动态的数据。由于没有指定名称则默认应用匿名插槽
关键字:slot
注意:
- 匿名插槽即将被废除,因此笔记仅借参考,建议使用具名插槽
- 如果组件标签当中未使用标签,则使用默认插槽中的数据
- 多个匿名插槽会拷贝多份标签中的数据进行填充
示例:
<div id="app">
<son>
<div>匿名插槽填坑1</div>
<div>匿名插槽填坑2</div>
<div>匿名插槽填坑3</div>
</son>
</div>
....
<template id="son">
<div>
<div>头部</div>
<slot>默认数据</slot>
<div>尾部</div>
</div>
</template>
<script>
new Vue({
el:"#app",
data:{},
components:{
"son": {
template:"#son"
}
}
});
</script>
渲染结果:
<div id="app">
<div>
<div>头部</div>
<div>匿名插槽填坑1</div>
<div>匿名插槽填坑2</div>
<div>匿名插槽填坑3</div>
<div>匿名插槽填坑1</div>
<div>匿名插槽填坑2</div>
<div>匿名插槽填坑3</div>
<div>尾部</div>
</div>
</div>
具名插槽
具体插槽 是通过name属性进行赋予插槽,因此可以指定使用插槽
应用方式:在模板中的 slot标签 添加属性 name属性值为名称 即可实现具体插槽
示例:
<div id="app">
<son>
<div slot="one">one内容11</div>
<div slot="two">two内容22</div>
</son>
</div>
....
<template id="son">
<div>
<div>头部</div>
<slot name="one">默认内容1</slot>
<slot name="two">默认内容1</slot>
<div>尾部</div>
</div>
</template>
<script>
new Vue({
el:"#app",
data:{},
components:{
"son":{
template:"#son"
}
}
});
</script>
渲染结果:
<div id="app">
<div>
<div>头部</div>
<div>one内容11</div>
<div>two内容22</div>
<div>尾部</div>
</div>
</div>
插槽作用域
插槽作用域 是带数据的插槽,数据在填充插槽时一般不会传递数据的因此需要手动进行传递数据,否则无法应用
传递方式有两种:
-
具名插槽的传递 ==#<插槽名>="<自定义获取名>"==
-
匿名插槽的传递
==slot-scope="<自定义获取名>"==
应用步骤:
- 在模板插槽的 slot标签中 添加 vue指令 ==v-bind:<数据名> = "<参数>"== (可缩写 缩写:==:names="list"== (list为名称的数组数据)
- 在父组件模板中的 插槽填充标签里以以下两个方式进行应用获取数据 ==#<插槽名>="<自定义获取名>"==/==slot-scope="<自定义获取名>"==
注意:
- #<插槽名>="<自定义获取名>" 的用法是给具体插槽进行应用的
- slot-scope="<自定义获取名>" 的用法是给 匿名/标签 插槽进行应用
- 匿名插槽的默认名称为 default ,也可通过该插槽名称进行传递数据
<div id="app">
<father></father>
</div>
....
<template id="Father">
<son>
<!-- 具体插槽应用 -->
<template #one="alist">
具体插槽 填充内容: {{alist.namelist1}}
</template>
<!-- 标签指定具体插槽应用 -->
<div slot="two" slot-scope="alist">
标签指定具体插槽 填充内容: {{alist.namelist2}}
</div>
<!-- 匿名插槽应用 -->
<template slot-scope="blist">
匿名插槽 填充内容: {{blist.namelist3}}
</template>
</son>
</template>
<template id="Son">
<div>
<div>头部</div>
<div>当前数据: {{list}}</div>
<!-- 将当前与的数据进行传递给 插槽填充的数据进行应用 -->
<!-- 指令应用原意:v-bind:<数据名> = "<参数>" -->
<slot :namelist1="list" name="one">具体插槽 默认内容: {{list}}</slot>
<br>
<slot :namelist2="list" name="two">具体插槽 默认内容: {{list}}</slot>
<br>
<slot :namelist3="list">匿名插槽 默认内容:{{list}}</slot>
<div>尾部</div>
</div>
</template>
<script>
new Vue({
el:"#app",
data:{},
components:{
"father":{
template:"#Father",
components:{
"son":{
template: "#Son",
data(){
return{
list:['张三','李四','王五','赵六']
}
}
}
}
}
}
})
</script>
渲染结果:
<div id="app">
<div>
<div>头部</div>
<div>当前数据: ["张三","李四","王五","赵六"]</div>
具体插槽 填充内容: ["张三","李四","王五","赵六"]
<br>
<div>标签指定具体插槽 填充内容: ["张三","李四","王五","赵六"]
</div>
<br>
匿名插槽 填充内容: ["张三","李四","王五","赵六"]
<div>尾部</div>
</div>
</div>
插值表达式
**作用:**将绑定的数据实时的显示出来
形式:=={{插值表达式}}==
**用法:**JS表达式、三目运算符、方法调用
示例
<body>
<div id="app">
<!-- js表达式 -->
<p>{{1+2+3}}</p>
<p>{{1>2}}</p>
<p>{{name+'很帅'}}</p>
<p>{{count+1}}</p>
<!-- 三目运算 -->
<p>{{count===1?"成立":"不成立"}}</p>
<p>{{list}}</p>
<!-- 方法调用 -->
<p>{{ip.split('.').reverse().join(':')}}</p>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
name: '张三',
count: 1,
list: [1,2,3].reverse(),
ip: "127.0.0.1"
}
})
</script>
</body>
<!-- 浏览器结果
6
false
张三很帅
2
成立
[ 3, 2, 1 ]
1:0:0:127
-->
Vue指令
v-text与v-html
v-text
- 作用:更新 整个 标签中的内容
- 插值表达式:更新标签中局部内容
v-html
- 作用:更新 标签中的 内容和标签
- 可渲染html标签的内容
- 经量避免使用防止XSS脚本攻击
示例
<body>
<div id="app">
<!-- v-text指令的值会替换标签内容 -->
<p v-text="msg">老哥 真的很帅</p>
<!-- v-html指令的值(包括标签字符串)会替换掉标签的内容 -->
<p v-html="msg2">老哥 真的很帅</p>
</div>
<script src="vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
msg: '老鸽',
msg2:'<span>老鸽2</span>'
}
})
</script>
</body>
v-if与v-show
v-if
- 作用:布尔值 决定元素的 添加 或 删除
- 值:布尔值
- 用于 条件少改变 的应用
v-show
- 作用:布尔值 决定元素的 显示 或 隐藏
- 值:布尔值
- 用于 频繁切换 的应用
示例
<body>
<div id="app">
<p v-if="isShow">张三</p>
<p v-show="isShow">李四</p>
</div>
<script src="vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
isShow: false
}
})
</script>
</body>
<!-- 浏览器 审查元素查看结果
<div id="app">
<p style="display: none;">李四</p>
</div>
->
v-on
**作用:**指令监听 DOM事件 ,进行 JS响应
**值&事件:**使用方式 (两种)
- ==v-on:事件名="方法名"==
- ==@事件名="方法名"==
**修饰符:**封装逻辑的方法
使用:==@事件名.修饰符="方法名"== @contextmenu.prevent
**事件对象:**向方法返回对象的本身
- 方法名传参
$event传递 ==方法名($event)== - 默认第一个event事件参数 ==方法名== (实参接收时传递的第一个参数是 event对象)
element.preventDefault() 阻止默认事件行为
**API:**cn.vuejs.org/v2/guide/ev…
监听事件
| 监听事件 | 说明 |
|---|---|
@click | 鼠标点击 |
@keyup | 键盘点击 |
事件修饰符
| 修饰符 | 说明 |
|---|---|
.once | 只触发一次 |
.prevent | 阻止 默认事件行为 |
.stop | 阻止 冒泡函数行为 |
.self | 只响应当前元素触发的行为(会受 冒泡影响 |
.capture | 添加事件监听器 |
示例
<body>
<div id="app">
<p>{{count}}</p>
<!-- 应用 -->
<!-- 触发按钮事件 -->
<button v-on:click="add">v-on Add1</button><br>
<button @click="add">@ Add1</button><br>
<!-- 修饰符 -->
<!-- 只能点击一次 -->
<button @click.once="add">.noce Add1</button><br>
<!-- 禁止右键菜单 -->
<button @contextmenu.prevent="add" @click="add">.prevent Add1</button><br>
<!-- 获取事件对象 -->
<button @click="add($event)">($event) add1</button><br>
<button @click="add2">add2</button><br>
</div>
<script src="vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
count:1
},
methods:{
add(e){
console.log(e);
this.count++;
},
add2(e){
console.log(e);
this.count++;
}
}
})
</script>
</body>
<!--
执行方法测试
-->
v-for
- 作用:渲染指定数组列表(遍历数组)
- 值:==item in items== 或 ==item of items== ( items 是数组的别名
- 支持参数选项
item(迭代数组的单个元素)、index(下标数)、key(主键) - 如果数组使用有
key,则每个元素都要有key,而且key是唯一的 - v-for 写的位置 不是父级标签,而是 重复本身的标签!!(循环的是标签本身
使用带有
key的数组 ,更新会更快, 因 根据key的更变进行更变,key是需要手动指定
示例
<body>
<div id="app">
<p>in 和 of</p>
<p><span v-for="item in list">{{item}} </span></p>
<p><span v-for="item of list">{{item}} </span></p>
<p>============</p>
<!-- v-for 支持参数选项 -->
<p>index 选项</p>
<ul v-for="(item , index) in items">
<li>{{index}} : {{item.name}}---{{item.sex}} </li>
</ul>
<p>============</p>
<p>key 选项</p>
<ul>
<li v-for="(v,i) in items":key="i">{{v}} --- {{i}}</li>
</ul>
<ul>
<li v-for="(v,i,k) in json":key="k">{{i}} -- {{k}} -- {{v}}</li>
</ul>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
list : ['a','b','c','d'],
items:[
{name:"张三",sex:"男"},
{name:"李四",sex:"女"},
{name:"王五",sex:"男"},
{name:"赵六",sex:"男"}
],
json : {
"001":{name:"智乃"},
"002":{name:"琪露诺"},
"003":{name:"蕾姆"},
"004":{name:"猫羽雫"}
}
}
})
</script>
</body>
<!-- 浏览器结果
in 和 of
a b c d
a b c d
============
index 选项
0 : 张三---男
1 : 李四---女
2 : 王五---男
3 : 赵六---男
============
key 选项
{ "name": "张三", "sex": "男" } --- 0
{ "name": "李四", "sex": "女" } --- 1
{ "name": "王五", "sex": "男" } --- 2
{ "name": "赵六", "sex": "男" } --- 3
001 -- 0 -- { "name": "智乃" }
002 -- 1 -- { "name": "琪露诺" }
003 -- 2 -- { "name": "蕾姆" }
004 -- 3 -- { "name": "猫羽雫" }
-->
v-bind
**作用:**绑定标签中上任意属性,对此属性值进行动态同步
**值:**值对象/[数组对应值] (支持三目运算符
**参数:**指定属性对应的值
编写:==v-bind:<属性名>== 缩写为: ==:<属性名>==
id
==:id="<变量名>"==
// id指定的值为 "myId"
<p :id="ID"></p>
data: {
ID:"myId";
}
class
Model:==:class="{<类值>:<布尔值> [, <类值>:<布尔值>]}"==
Model:==:class="<属性名>"== (指定的是对象
原生class:==:class="[<类名> [, <类名>] ]"==
注意:
- 绑定class和原生class 不会合并重复,会优先去Model中找数据值
- 如果想在当中使用原生class样式名,将对象以数组的形式写进去,以防在Model中查找 例如: :class="['box']" (可以写多个原生class类名)
<!-- class 对象 -->
<!-- class结果值为:class="left right left" -->
<p class="left right" :class="{left:a,rigth:b}"></p>
<!-- class 数组 -->
<!-- class结果值为:class="left right left2 rigth2" -->
<p class="left right" :class="[aa,bb]"></p>
<!-- class 封装对象 -->
<!-- class结果值为:class="a" -->
<p :class="obj"></p>
data: {
a:true,
b:false,
aa: "left2",
bb: "rigth2",
obj:{
a:true,
b:false
}
}
style
==:style="{<样式名>:<样式值> [, <样式名>:<样式值>]}"==
==:style="[<变量名/对象名> [, <变量名/对象名>] ]"==
注意:
- 如果用对象形式,则样式值一定要有 单引号/双引号 包围,否则样式无效
- 数组形式可以 直接写入样式 或 对象样式
<!-- style 对象 -->
<p :style="{background:a,width:b,height:c}"></p>
<!-- style 数组 -->
<p :style="[aa,bb,cc]"></p>
data: {
a : "black",
b : "100px",
c : "100px",
aa : {"background":"red"},
bb : {"width":"100px"},
cc : {"height":"100px"},
}
v-model
- 作用:绑定表单组件上任意属性,对此值进行动态同步
- 值:变量名
作用标签
| 标签 | 绑定属性值 |
|---|---|
| ==input[type='text']== | value |
| ==textarea== | value |
| ==input[type='checkbox']== | checked |
| ==input[type='radio']== | checked |
| ==select>option== | value |
注意: v-model 会忽略表单组件中的 value、checked、selected attribute 的初始值,而数据的来源在 Vue 实例中
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--
- text 和 textarea 元素使用 value property 和 input 事件
- checkbox 和 radio 使用 checked property 和 change 事件
- select 字段将 value 作为 prop 并将 change 作为事件
-->
<form action="#">
<!-- text -->
<input type="text" v-model="msg" value="柏竹">
<p>{{msg}}</p>
<!-- textarea -->
<textarea v-model="msg2" cols="30" rows="3"></textarea>
<p>{{msg2}}</p>
<!-- radio -->
sex:
<label>女<input type="radio" value="女" name="sex" v-model="picked"></label>
<label>男<input type="radio" value="男" name="sex" v-model="picked"></label>
<p>check:{{picked}}</p>
<!-- checkbox -->
hobby:
<label> <input type="checkbox" name="hobby" value="篮球" v-model="checked">篮球</label>
<label> <input type="checkbox" name="hobby" value="网球" v-model="checked">网球</label>
<label> <input type="checkbox" name="hobby" value="足球" v-model="checked">足球</label>
<label> <input type="checkbox" name="hobby" value="羽毛球" v-model="checked">羽毛球</label>
<label> <input type="checkbox" name="hobby" value="乒乓球" v-model="checked">乒乓球</label>
<label> <input type="checkbox" name="hobby" value="气排球" v-model="checked">气排球</label>
<p>checked:{{checked}}</p>
<!-- select -->
<select v-model="selected">
<option value="篮球" selected>篮球</option>
<option value="网球">网球</option>
<option value="足球">足球</option>
<option value="羽毛球">羽毛球</option>
<option value="乒乓球">乒乓球</option>
<option value="气排球">气排球</option>
</select>
<p>selected:{{selected}}</p>
</form>
</div>
</body>
<script src="vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
msg:"张三",
msg2:"李四",
picked: '',
checked:[],
selected:''
}
});
</script>
</html>
v-cloak
**作用:**解决页面初次渲染时 出现 {{}} 的问题
步骤:
-
为
v-cloak指令 添加CSS规则[v-cloak] { display: none; } -
为 vue实例的容器 添加 指令
v-cloak<div id="app" v-cloak> ... </div>
v-once
作用: 在所在的元素只渲染一次
步骤: 为指定标签 添加 v-once指令 (前提该标签在Vue容器范围内
v-slot
**作用:**指定当前标签中的子标签内容填充至插槽中(点击插槽了解
编写:==v-slot:<插槽名>== 缩写为:==#<插槽名>==
注意 :
- 该指令只能用在 template标签 中进行使用该该指令
- v-slot指令 vue2.6以上版本才能应用
示例:
<div id="app">
<son>
<template v-slot:one>
<p>模板数据填充1</p>
<p>模板数据填充11</p>
</template>
<template #two>
<p>模板数据填充2</p>
<p>模板数据填充22</p>
</template>
</son>
</div>
....
<template id="son">
<div>
<div>头部</div>
<slot name="one">默认数据1</slot>
<slot name="two">默认数据2</slot>
<div>尾部</div>
</div>
</template>
<script>
new Vue({
el:"#app",
data:{},
components:{
"son":{
template:"#son"
}
}
});
</script>
渲染结果:
<div id="app">
<div>
<div>头部</div>
<p>模板数据填充1</p>
<p>模板数据填充11</p>
<p>模板数据填充2</p>
<p>模板数据填充22</p>
<div>尾部</div>
</div>
</div>
自定义指令
**作用:**对 DOM元素 进行底层操作
类型: 全局/局部 自定义指令
**API:**cn.vuejs.org/v2/guide/cu…
步骤:
-
定义 自定义指令 全局/局部 全局自定义指令
Vue.directive(<指令名称>, { <钩子函数>: function (e [, <参数>]) { // e参数 DOM对象本身 ... } })局部自定义指令
new Vue({ el: "...", data: {...}, directives: { <指令名称1>:{ <钩子函数>: function (<钩子函数参数>) { ... } } [, <指令名称2>:{ <钩子函数>: function (<钩子函数参数>) { ... } }] } }); -
在指定元素添加 自定义指令 实现功能 ==v-<指令名称>==
钩子函数
bind:只调用一次,指令第一次绑定到元素时调用unbind:只调用一次,指令与元素解绑时调用inserted:被绑定元素插入父节点时调用
钩子函数参数
el:被绑定的当前元素的 DOM对象binding:指令本身数据,包含有以下属性name:指令名称 不包括v-前缀value:指令绑定值 包含表达式运算结果 如 v-my="1+1" 最后结果值为 2expression:字符串形式的指令表达式(属性名arg:传给指令的参数 v-my:funcc 中 ,则 参数为 funccmodifiers:包含修饰符的对象 v-my.foo.bar 中,修饰符对象为 {foo: true , bar: true}
示例:
<div id="app">
<div v-demo:foo.a.b="msg"></div>
</div>
...
<script>
new Vue({
el: "#app",
data: {
msg: "hello"
},
directives: {
demo: {
bind: function (el, binding, vnode) {
// 将 binding对象 转化为 JOSN格式
var s = JSON.stringify;
el.innerHTML =
'name : ' + s(binding.name) + "<br>" +
'value : ' + s(binding.value) + "<br>" +
'expression : ' + s(binding.expression) + "<br>" +
'arg : ' + s(binding.arg) + "<br>" +
'modifiers : ' + s(binding.modifiers) + "<br>" +
'Object.keys : ' + Object.keys(vnode).join(',');
}
}
}
});
</script>
//控制台
name : "demo"
value : "hello"
expression : "msg"
arg : "foo"
modifiers : {"a":true,"b":true}
Object.keys : tag,data,children,text,elm,ns,context,fnContext,fnOptions,fnScopeId,key,componentOptions,componentInstance,parent,raw,isStatic,isRootInsert,isComment,isCloned,isOnce,asyncFactory,asyncMeta,isAsyncPlaceholder
Vue属性
key
**作用:**在虚拟DOM中的节点添加 ID
**缘故:**在数组遍历时可能出现相同DOM节点的元素,容易出现数据混乱的问题,因此需要独有的key进行排列调整,这一前提key必须具有唯一性
<ul>
<li v-for="item in items" :key="item.id">...</li>
</ul>
应用场景:
强制替换元素/组件而不是重复使用:
- 完整地触发组件的生命周期钩子
- 触发过渡
<!-- 当 text 发生改变时,<span> 总是会被替换而不是被修改,因此会触发过渡。 -->
<transition>
<span :key="text">{{ text }}</span>
</transition>
ref
**作用:**获取被 ref属性 的标签 DOM对象(该标签在Vue容器范围内
值: DOM对象获取的引用
注意:
- 当 ref 和 v-for 共存时,得到的 DOM对象 将会是一个包含对应数据源子组件数组
- $ref 只会在标签渲染后生效,并非是响应式的,因此竟可能的避免在 模板/算法 中使用
- $ref 也可获取组件标签中的 DOM对象 信息
**步骤: **
- 为需要获取 DOM对象的标签添加
ref属性 并赋予值 - 获取 DOM对象 可直接通过以下方式获取 ==this.$refs.<ref属性值>==
示例:
<div id="app">
<son ref="myMsg"></son>
<button @click="log">log</button>
</div>
....
<template id="son">
<div>
<p>我是组件</p>
<p>{{msg}}</p>
</div>
</template>
<script>
Vue.component("son", {
template: "#son",
data() {
return{
msg:"hello"
}
},
methods:{
say() {
console.log("load... Say()")
}
}
})
new Vue({
el: "#app",
data: {
msg: "hello"
},
methods: {
log() {
console.log(this.$refs.myMsg)
console.log(this.$refs.myMsg.msg)
console.log(this.$refs.myMsg.say)
}
}
});
</script>
slot
**作用:**标记往哪个具名插槽中插入子组件内容
示例:跳转示例
slot-scope
**作用:**接收插槽传递的数据
示例:跳转示例
Vue通信
作用: 在 Vue.js 中发出请求(本质和Ajax一样
**API:**www.kancloud.cn/yunye/axios…
**API2:**cn.vuejs.org/v2/cookbook…
**API3 : ** www.axios-http.cn/docs/intro
**CDN:**unpkg.com/axios@0.26.…
**开源:**www.npmjs.com/package/jso…
关键字:json-server 、axios.js
插件应用前提:(可跳过) 本地调用的 json库,如果没有通过以下步骤操作
- 安装
node.js(nodejs.org/zh-cn/ - 配置环境 将
node.js根路径 配至 Path 变量中 (添加值,并非覆盖 - 测试安装 cmd 执行指令 ==node -v== (返回版本号代表成功
- 安装 Json本地调试 cmd执行命令 ==npm i json-server==/==npm install -g json-server== (其中一个
- 配置 Window脚本运行策略 (系统默认是未签名运行
- 菜单搜索
powershell(管理员运行) - 更改签名 执行命令 ==set-ExecutionPolicy RemoteSigned==
- 菜单搜索
- 任意一终端(cmd) 执行 ==json-server <数据文件.json>== (手动指定路径/终端跳转到指定路径下
json-server 指令选项
| 参数 | 简写 | [类型] 默认值 | 说明 |
|---|---|---|---|
| --config | -c | [String] "json-server.json" | 指定配置文件 |
| --port | -p | [Number] 3000 | 设置端口 |
| --host | -H | [String] "localhost" | 设置域 |
| --watch | -w | [boolean] | 是否监听 |
| --routes | -r | [String] "" | 指定自定义路由 |
| --middlewares | -m | [Array] | 指定中间件 files |
| --static | -s | [String] | 设置静态目录 |
| --read-only | --ro | [boolean] | 只允许 GET请求 |
| --no-cors | --nc | [boolean] | 是否禁用 跨域资源共享 |
| --no-gzip | --ng | [boolean] | 是否禁用 GZIP 内容编码 |
| --id | -i | [String] "id" | 设置数据库 id 属性 |
| --delay | -d | [Number] | 增加响应延迟(ms) |
| --snapshots | -S | [String] "." | 设置快照目录 |
| --foreignKeySuffix | --fks | [String] "Id" | 设置外键后缀 |
| --quiet | -q | [boolean] | 禁止输出中的日志消息 |
| --help | -h | [boolean] | 显示帮助信息 |
| --version | -v | [boolean] | 显示版本号 |
步骤:
-
引入插件 axios.js
-
启动 json-server本地库
-
请求语法
axios.get(url).then((res) => { // 请求成功 会来到这 res响应体 }).catch((err) => { // 请求失败 会来到这 处理err对象 })
其他请求实例 (用户列表
// 获取
axios.get('http://localhost:3000/brands').then().catch()
// 删除
axios.delete('http://localhost:3000/brands/1').then().catch()
// 添加
axios.post('http://localhost:3000/brands', {name: '小米', date: new Date()}).then().catch()
// 修改
axios.put('http://localhost:3000/brands/1', {name: '小米', date: new
Date()}).then().catch()
// get模糊搜索
axios.get("http://localhost:3000/brands?name_like=" + "aaa").then().catch()
注意:
- 选项computed 计算属性查询 返回的结果是行不通,因 查询请求是异步返回数据的
- 选项computed 计算属性 一定要是同步操作,异步逻辑则失效
- 异步请求可通过 选项watch 监听 data数据
请求头一般关注的属性有 :
Content-TypeAccept
axios.js库 通信默认使用 json格式 , 如果自定义以下的格式 :
- ==application/json== (默认)
- ==application/x-www-form-urlencoded==
- ==multipart/form-data==
模板用例 :
axios.post(
URL, params,
{ headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'
} })
.then(res => {
if (res.data.code === 0) {
this.$router.go(-1)
}
}).catch(error => {
alert('更新用户数据失败' + error)
})
ue路由
作用: 让 页面 构建单页应用变得简单
CDN: lib.baomitu.com/vue-router/…
**API:**router.vuejs.org/zh/api/
关键字: router 、routes
注意:
- js库引入顺序 优先引入vue后则引入vue-router(基于vue运行的)
- 路由的参数传递 需要到 $route对象 进行传递参数
-
router-link标签 渲染默认是 a标签,如有想渲染其他标签,可通过tag属性值为 指定的标签名
应用步骤:
-
引入 vue 和 vue-router库
-
设置 HTML内容
<div id="app"> <!-- router-link 最终会被渲染成a标签,to指定路由的跳转地址 --> <router-link to="/users">用户管理</router-link> <router-link to="/home">首页展示</router-link> <!-- 路由匹配到的组件将渲染在这里 --> <router-view></router-view> </div> -
创建 路由对应的Vue组件的模板
let Home = { template: '<div>这是Home内容</div>' }; let Users = { template: '<div>这是用户管理内容</div>' }; -
配置路由规则
routes不建议更变 (在实例对象中,如果更变了名称则匹配不到该对象let routes = [ { path: '/users', component: Users } { path: '/home', component: Home } ]; -
实例路由对象
router不建议更变 (在实例对象中,如果更变了名称则匹配不到该对象let router = new VueRouter({ routes }) -
router实例 挂载到 vue实例上
new Vue({ el: '#app', router })
示例:
<div id="app">
<!-- 2. 设置HTMl内容 -->
<!-- router-link 最终会想渲染成a标签,to指定路由的跳转地址 -->
<router-link to="/home">主页</router-link>
<router-link to="/top">热点</router-link>
<router-link to="/abouts">关于</router-link>
<!-- <显示的内容> -->
<router-view></router-view>
</div>
<!-- 1. 引入库 -->
<script src="vue.js"></script>
<script src="vue-router.js"></script>
<script>
// 4. Vue组件
let Home = {
template:"<div>主页内容</div>"
}
let Top = {
template:"<div>热点内容</div>"
}
let Abouts = {
template:"<div>关于内容</div>"
}
// 3. 设置路由规则
let router = new VueRouter({
routes: [
{path:"/home",component: Home },
{path:"/top",component: Top },
{path:"/abouts",component: Abouts }
]
});
// 5. 把router实例挂载到vue实例上
new Vue({
el: "#app",
router
});
</script>
动态路由
动态路由 是 通过在跳转过程对参数的一个携带过程,在当中有两种方式进行传递数据
- 原生URL
- 动态路由Path携带 (REST风格
应用步骤:
-
设置HTML内容,并引入参数 (假如传递参数 : =={name: '张三', age: 23}==
<!-- 原生URL传参 --> <router-link to="/item?name=张三&age=23">张三1</router-link> <!-- 动态路由传参 --> <router-link to="/item/张三/23"></router-link> -
动态路由规则 动态参数进行接收,接收方式
:<参数名>(参数的属性名称随意new VueRouter({ routes:[ {path:'/item/:name/:age',component: ...} ] })**PS:**原生URL传递无需经通过第二步骤进行 Path路由地址的设置
-
两种传递方式接收各有不同 (因 $route对象 存储参数位置不一样
- 原生URL:==this.$route.query.<参数名>==
- 动态路由:==this.$route.params.<参数名>==
**PS:**路由跳转时可在组件中添加
update()函数 ,在DOM重新渲染后,对数据进行打印
示例:
<div id="app">
<router-link to="/item?id=23">小明</router-link>
<router-link to="/item?id=23&name=小华">小华</router-link>
<router-link to="/item/33/小军">小军</router-link>
<router-view></router-view>
</div>
....
<template id="show">
<div>
<p>传递的数据查看</p>
<ul>
<li>params.id: {{this.$route.params.id}}</li>
<li>params.name: {{this.$route.params.name}}</li>
<li>params.age: {{this.$route.params.age}}</li>
<li>query.id: {{this.$route.query.id}}</li>
<li>query.name: {{this.$route.query.name}}</li>
<li>query.age: {{this.$route.query.age}}</li>
</ul>
</div>
</template>
<script>
let Items = {
template: "#show",
// DOM 重新渲染完成后被调用 (用于测试
updated() {
console.log(this.$route);
}
}
let router = new VueRouter({
routes: [
{path: '/item/:id', component: Items},
{path: '/item/:id/:name/:age', component: Items}
]
})
new Vue({
el: "#app",
router
})
</script>
路由 to属性赋值
路由的 to属性 可提高路由的利用和便捷
- 常规跳转 ==aaa==
- 变量值 ==aaa==
- 对象name跳转 ==aaa==
- 对象path跳转 ==aaa==
- 带参数跳转 ==aaa==
示例:
<div id="app">
<!-- 常规 -->
<router-link to="/aaa">aaa</router-link>
<!-- 变量 -->
<router-link :to="bbb">bbb</router-link>
<!-- 对象name -->
<router-link :to="{name:'ccc'}">ccc</router-link>
<!-- 对象path -->
<router-link :to="{path:'/ddd'}">ddd</router-link>
<!-- 带参数跳转 -->
<router-link :to="{name:'eee',params:{id:1,name:'张三'}}">eee</router-link>
<br>
<router-view></router-view>
</div>
...
<script>
let AAA = {
template:'<div>AAA</div>'
}
let BBB = {
template:'<div>BBB</div>'
}
let CCC = {
template:'<div>CCC</div>'
}
let DDD = {
template:'<div>DDD</div>'
}
let EEE = {
template:'<div>EEE<br>参数: {{$route.params.id}} : {{$route.params.name}} </div>'
}
let router = new VueRouter({
routes:[{
path:"/aaa",
component: AAA
},{
path:"/bbb",
component: BBB
},{
name:"ccc",
path:"/ccc",
component: CCC
},{
path:"/ddd",
component: DDD
},{
name:"eee",
path:"/eee",
component: EEE
}]
})
new Vue({
el:"#app",
data:{
bbb:'/bbb'
},
router
})
</script>
redirect重定向
当某个页面被强制中转时,采用 redirect 进行路由重定向
关键字:redirect
步骤: 在原有的路由组件里 添加新 属性 ==redirect : <路由地址>==
routes:[{
path : <默认路由地址>,
redirect : <重定向路由地址>
}]
实例:(将 /bbb 路由强制中转至 /aaa
<div id="app">
<router-link to="/aaa">aaa</router-link>
<router-link to="/bbb">bbb</router-link>
<router-link to="/ccc">ccc</router-link>
<router-view></router-view>
</div>
....
<script>
let AAA = {
template:'<div>AAA</div>'
}
let BBB = {
template:'<div>BBB</div>'
}
let CCC = {
template:'<div>CCC</div>'
}
let router = new VueRouter({
routes:[{
path:'/aaa',
component:AAA
},{
path:'/bbb',
redirect:"/aaa",
component:BBB
},{
path:'/ccc',
component:CCC
}]
});
new Vue({
el:"#app",
data:{},
router
});
</script>
编程式导航
以 点击事件形式 来点击某一标签,实现路由跳转功能
关键字:this.$router.push
步骤: 在 Vue容器添加方法用于 事件响应,执行 this.$router.push对象
<方法名>() {
this.$router.push({
path:<路由地址>
});
}
示例:(按钮实现路由AAA
<div id="app">
<router-link to="/aaa">aaa</router-link>
<button @click="toAAA">aaa编程式</button>
<router-view></router-view>
</div>
...
<script>
let AAA = {
template:'<div>AAA</div>'
}
let router = new VueRouter({
routes:[{
path:'/aaa',
component:AAA
}]
});
new Vue({
el:"#app",
data:{},
methods:{
toCCC() {
this.$router.push({
path:"/aaa"
});
}
},
router
});
</script>
路由激活样式
路由激活会产生样式 ==calss="router-link-exact-active router-link-active"==,该类会伴随着激活出现
<a href="..." class="router-link-exact-active router-link-active">切换页面1</a>
以上的 激活样式的系统类名,一般不建议直接覆盖系统默认的样式,因此官方提供有方式修改其样式
自定义路由激活class样式 :在路由规则中 添加 linkActiveClass属性其值为 class名
路由激活渲染示例: (la-active为自定义样式的class名)
<a href="..." class="router-link-exact-active la-active">切换页面1</a>
路由嵌套
路由嵌套和二级菜单 类似,但二级路由的嵌套是通过组件模板中再次添加路由,从而实现路由嵌套的效果
关键字:children
应用步骤:
- 在一级路由组件的
component模板中 添加二级路由的模板 - 在一级路由的路由规则里 添加属性
children数组 - 在
childern数组 中配置二级路由规则与模板
let routes = [{
path: <一级路由地址>,
component: <一级路由模板>,
children: [
{path: <二级路由地址>, component: <二级路由模板>}
[,{path: <二级路由地址>, component: <二级路由模板>}...]
]
}
[,{path: <一级路由地址>, component: <一级路由模板2>}...]
]
注意:
- 该路由为子路由,那么无需再次编辑一级路径地址,也可无需添加反斜杠 /
<div id="app">
<router-link to="/home">主页</router-link>
<router-link to="/music">音乐</router-link>
<router-view></router-view>
</div>
...
<script>
let Home = {
template:'<div>Home---</div>'
}
let Music = {
template: '<div>MUSIC---' +
'<router-link to="/music/pop">流行</router-link>' +
'<router-link to="/music/cal">古典</router-link>' +
'<router-view></router-view>' +
'</div>'
}
//二级组件
let Detail = {
template: '<div>Detail--{{$route.params.name}}</div>'
}
let router = new VueRouter({
routes:[{
name:'default',
path:'/',
component: Home
},{
name:'home',
path:'/home',
component: Home
},{
name:'music',
path:'/music',
component: Music,
// 子路由
children:[{
path:'/music/:name',
component: Detail
}]
}]
});
new Vue({
el:"#app",
data:{},
router
});
</script>
示例2:
<style>
.box-red {
background: red;
height: 200px;
}
.box-blue {
background: blue;
height: 200px;
}
.box-green {
background: green;
height: 200px;
}
</style>
....
<div id="app">
<router-link to="/one">路由页面1</router-link>
<router-link to="/two">路由页面2</router-link>
<router-view></router-view>
</div>
....
<template id="one">
<div class="box-green">
<p>一级one</p>
<router-link to="/one/onesub1">路由页面1</router-link>
<router-link to="/one/onesub2">路由页面2</router-link>
<router-view></router-view>
</div>
</template>
<template id="onesub1">
<div class="box-red">
<p>二级one</p>
</div>
</template>
<template id="onesub2">
<div class="box-blue">
<p>二级one</p>
</div>
</template>
<template id="two">
<div class="box-green">
<p>一级two</p>
</div>
</template>
<script>
let One = {
template: "#one"
}
let Two = {
template: "#two"
}
let OneSub1 = {
template: "#onesub1"
}
let OneSub2 = {
template: "#onesub2"
}
let routes = [
{path: "/", redirect: '/one'},
{
path: "/one",
component: One,
children: [
{path: "onesub1", component: OneSub1},
{path: "onesub2", component: OneSub2}
]
},
{path: "/two", component: Two}
]
let router = new VueRouter({
routes
})
new Vue({
el: "#app",
router
})
</script>
命名视图
命名视图 是让不同出口显示不同内容(和 具名插槽 类似)
当路由地址被匹配时同时制定多个出口,并且每个出口显示的内容不一样
应用步骤:
- 为
router-view标签 添加 name属性(指定出口类型的模板 - 在 路由规则配置中 将路由模板从
component属性 改为components属性 (添加模板组
let router = new VueRouter({
routes: [{
path: <路由地址>,
// key值 对应路由出口的 name属性值
components: {
<key>: <模板1>
[,<key>: <模板2>...]
}
}]
})
示例:
<div id="app">
<router-view></router-view>
<router-view name="name1"></router-view>
<router-view name="name2"></router-view>
</div>
....
<template id="one">
<div>
<p>第一个模板</p>
</div>
</template>
<template id="two">
<div>
<p>第二个模板</p>
</div>
</template>
<script>
let One = {
template: "#one"
}
let Two = {
template: "#two"
}
// 首次打开网页URL路由地址为 '/'
let routes = [{
path: "/",
components: {
name1: One,
name2: Two
}
}]
let router = new VueRouter({
routes
})
new Vue({
el: "#app",
router
})
</script>
渲染结果:
<div id="app">
<!---->
<div><p>第一个模板</p></div>
<div><p>第二个模板</p></div>
</div>
三个出口:
- 未指定出口名称因此没有显示
- 指定出口名称为 name1 -> One
- 指定出口名称为 name2 -> Two
路由监听
[watch属性](#watch 数据监听) 不仅仅能够监听数据的变化,还能够监听路由地址的变化
监听方式:
watch: {
"$route.path"(newV, oldV) {
console.log(newV, oldV)
}
}
Vue其他
过渡动画
Vue 内置的过渡组件,transition 组件用于嵌套要实现过渡效果,在当中的组件 添加/删除 实现了 进入/离开 的过渡效果
关键字:transition
步骤:
-
先创建
transition组件,且设置 name属性 (一定要name属性<transition name="my"> <!-- 产生动画的标签 --> </transition> -
在
transition组件 内设置 产生过渡动画的标签,并添加 ==v-if=<boolean是否显示>==属性 -
添加样式实现即可
过渡动画 class样式 :
class样式的前缀名称为 transition标签 中的 name属性值
进入 class样式
| class(transition标签 name属性值为fade | 说明 |
|---|---|
| ==fade-enter== | 进入 初始状态 |
| ==fade-enter-to== | 进入 结束状态 |
| ==fade-enter-active== | 进入 过渡效果 |
离开 class样式
| class(transition标签 name属性值为fade | 说明 |
|---|---|
| ==fade-leave== | 离开 初始状态 |
| ==fade-leave-to== | 离开 结束状态 |
| ==fade-leave-active== | 离开 过渡效果 |
示例:
<style>
*{
margin: 0;
padding: 0;
}
.box {
width: 200px;
height: 200px;
background: #00A1DA;
/*绝对定位:相对浏览器*/
position: absolute;
}
button{
position: absolute;
top: 200px;
}
.my-enter-to,
.my-leave{
left: 0;
/*透明度*/
opacity: 1;
}
.my-enter,
.my-leave-to{
left: 200px;
opacity: 0;
}
.my-enter-active,
.my-leave-active{
/*过渡效果连写*/
transition: all 2s;
}
</style>
...
<div id="app">
<transition name="my">
<div class="box" v-if="isShow"></div>
</transition>
<button @click="toShow">按钮</button>
</div>
...
<script>
new Vue({
el: "#app",
data: {
isShow: true
},
methods: {
toShow() {
this.isShow = !this.isShow;
}
}
});
</script>
Vuex
Vuex 是 Vue中的一套 公共数据管理工具,可将数据存到 vuex中,方便整个程序在任何组件 获取和修改当中的公共数据
**API:**vuex.vuejs.org/zh/
GitHub: github.com/vuejs/vuex
**CDN:**cdn.bootcdn.net/ajax/libs/v…
关键字: store 、state
应用步骤: (前提:两层嵌套组件)
-
引入 vue.js
-
创建 实例vuex对象
const <vuex对象名> = new Vuex.Store({ state() { return { <key>:<value> [, <key>:<value> ...] } } }); -
父组件引入 vuex对象 ==store: <vuex对象名>==
Vue.component(<组件名>, { store: <vuex对象>, } -
应用 vuex数据,获取通过 插值表达式 进行获取
==this.$store.state.<属性key>==
示例:
<div id="app">
<grandpa></grandpa>
</div>
....
<template id="grandpa">
<div>
<p>爷爷 {{this.$store.state.msg}}</p>
<father></father>
</div>
</template>
<template id="father">
<div>
<p>父亲 {{this.$store.state.msg}}</p>
<son></son>
</div>
</template>
<template id="son">
<div>
<p>儿子 {{this.$store.state.msg}}</p>
</div>
</template>
<script>
const d = new Vuex.Store({
state() {
return {
msg: "hello world"
}
}
});
// 爷爷
Vue.component("grandpa", {
template: "#grandpa",
store: d,
components: {
// 父亲
"father": {
template: "#father",
components: {
// 儿子
"son": {
template: "#son"
}
}
}
}
})
new Vue({
el: "#app"
})
</script>
渲染结果:
<div id="app">
<div>
<p>爷爷 hello world</p>
<div>
<p>父亲 hello world</p>
<div>
<p>儿子 hello world</p>
</div>
</div>
</div>
</div>
方法共享
方法共享 可在不同组件之间均可使用的方法,vuex中 mutations对象 是专门保存操作共享数据的方法
关键字: mutations
一般情况不建议在组件中对Vuex共享数据直接修改,因为在多个组件中维护起来会比较麻烦。因此建议使用vuex共享的方法进行修改,维护时只需查看vuex的方法即可
注意:
- mutations中定义的方法,系统会自动传递 state参数(state保存的是共享数据
-
引入vuex.js
-
创建 实例Vuex对象
-
Vuex对象中编写方法
const <vuex对象名> = new Vuex.Store({ state() { return {....} }, mutations: { // 系统会自动传递 state参数 <方法名1>(state) { .... } [,<方法名2>(state) {....}] } }) -
父组件引入 vuex对象 ==store: <vuex对象名>==
-
组件方法调用vuex共享 ==this.$store.commit(<vuex对象方法名>[,<参数>])==
示例:
<div id="app">
<no1></no1>
</div>
....
<template id="no1">
<div>
<button @click="add">加</button>
<button @click="sub">减</button>
<input type="text" :value="this.$store.state.count">
<no2></no2>
</div>
</template>
<template id="no2">
<div>
<button @click="add2">加</button>
<button @click="sub2">减</button>
<input type="text" v-model.number="val">
<p>{{this.$store.state.count}}</p>
</div>
</template>
<script>
const b = new Vuex.Store({
state() {
return {
count: 1
}
},
mutations: {
// 系统会自动传递 state参数
mAdd(state) {
state.count += 1;
},
mSub(state) {
state.count -= 1;
},
// 带参测试
mAdd2(state , num) {
state.count += num;
},
mSub2(state , num) {
state.count -= num;
}
}
})
Vue.component("no1", {
template: "#no1",
store: b,
components: {
"no2": {
template: "#no2",
data() {
return {
val: 0
}
},
// 组件2 带参应用
methods: {
add2() {
this.$store.commit("mAdd2", this.val)
},
sub2() {
this.$store.commit("mSub2", this.val)
}
}
}
},
methods: {
add() {
this.$store.commit("mAdd")
},
sub() {
this.$store.commit("mSub")
}
}
})
new Vue({
el: "#app"
})
</script>
计算属性共享
[计算属性](#computed 计算属性) 是为了在多组件中完好的利用缓存,从而提高效率
关键字: getters
应用步骤:(上面已经有大致步骤,因此展示主要代码)
-
在 vuex实例中 添加
gettersconst <vuex对象名> = new Vuex.Store({ state() { return{ msg: "柏竹" } }, getters: { // 系统会自动传递 state参数 <计算属性名>(state) { console.log("执行了 formart") return state.msg + " Hello World " } } }) -
组件调用计算属性 ,获取通过 插值表达式 进行获取 ==this.$store.getters.<计算属性名>==
示例:
<div id="app">
<no1></no1>
</div>
....
<template id="no1">
<div>
<p>no1 {{this.$store.getters.formart}}</p>
<p>no11 {{this.$store.getters.formart}}</p>
<no2></no2>
</div>
</template>
<template id="no2">
<div>
<p>no2 {{this.$store.getters.formart}}</p>
<p>no22 {{this.$store.getters.formart}}</p>
</div>
</template>
<script>
const b = new Vuex.Store({
state() {
return{
msg: "柏竹"
}
},
getters: {
formart(state) {
console.log("执行了 formart")
return state.msg + " Hello World "
}
}
})
Vue.component("no1",{
template:"#no1",
store: b,
components:{
"no2":{
template: "#no2"
}
},
data() {
return{
msg: "柏竹"
}
}
})
new Vue({
el:"#app"
})
</script>
Vue-Cli
Vue-cli 存在的意义就是让开发人员把精力放在业务的代码上,因此其他的准备的工作交给vue-cli去做即可
**API:**cli.vuejs.org/zh/guide/
安装
全局脚手架
npm i -g @vue/cli
验证安装(查看版本
# 后面的 V 一定要大写
vue -V
创建项目
PS:项目名当中不能含有英文大写
# 4.0下创建 heroes项目
$ vue create heroes
# 切换到 项目根目录
$ cd heroes
# 在开发模式下 启动运行项目
$ npm run serve
....
# 打包项目
$ npm run build
以上指令在 ==package.json==文件 看到相关配置
项目配置
根目录下的 ==vue.config.js==文件
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: true, // 在保存代码的时候开启eslint代码检查机制
devServer: { // 实时保存、编译的配置段
open: true, // 自动开启浏览器
port: 12306 // 服务运行端口
}
})
项目目录
以下的Vue-Cli生成的项目结构解读
Vue-Cli不同版本的项目结构也会不同:
- ==2.x==版本 的项目结构中有 buiild文件夹和config文件夹 这两个文件夹存储了webpack相关的配置,当中可以根据项目需求修改webpack配置
- ==3+==版本 以后的版本项目结构中 已经隐藏了这两个文件夹 (主要目的是为了让初学者更关心怎么去用Vue,并非是 webpack配置相关的
.
|-- node_modules // 项目需要的依赖包
|-- public // 静态资源存储目录
| |-- index.html // 项目主容器文件
| |-- favicon.ico // 项目默认索引图片
|-- src
| |-- assets // 静态资源文件夹
| |-- components // 公共组件目录
| |-- views // 业务组件目录
| |-- App.vue // 顶层根基路由组件
| |-- main.js // 主入口文件
| |-- router.js // 路由配置文件
|-- .editorconfig // 代码规范配置文件
|-- .eslintrc.js // eslint代码规范检查配置文件
|-- .gitignore // git上传需要忽略的文件格式
|-- babel.config.js // babel配置文件
|-- package-lock.json // 依赖包版本锁定文件
|-- package.json // 项目基本信息配置文件
|-- postcss.config.js // css预处理器配置文件
|-- vue.config.js // webpack 配置文件
项目开发
开发主要应用有:Vuex、Router
在开发的时候编写代码主要围绕着 src/public 这两个文件夹,他们分别作用已经在上面叙述有。开发当中可能会受到不同版本的影响,因此专门分为 版本2 和 版本3+ 进行写开发应用示例
默认情况下生成 Vue-Cli脚手架 是官方已经配置好的,因此建议手动配置一次保存为好
手动配置安装选项:
dart-sass、babel、router、vuex、eslint
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex, CSS Pre-processors, Linter
? Choose a version of Vue.js that you want to start the project with 3.x
? Use history mode for router? (Requires proper server setup for index fallback in production) y
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass)
? Pick a linter / formatter config: Standard
? Pick additional lint features: Lint on save, Lint and fix on commit
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N) n
版本2开发
由于版本3 较为简洁说明用版本2
main.js
// 导入 库
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 创建实例
new Vue({
router,
store,
// 渲染组件
render: h => h(App)
}).$mount('#app')
App.vue
// 组件模板
<template>
</template>
// 组件脚本
<script>
export default {}
</script>
// 样式
<style lang="scss">
</style>
Vuex
./router/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vue)
const store = new Vuex.Store({
state: {
name: '柏竹'
}
})
// 暴露出去 给 App.vue 引用
export default store
Router
./store/index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const router = new Router({
routes: [...]
})
export default router
版本3+开发
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App).use(store).use(router).mount('#app')
App.vue
<template>
</template>
<script>
export default {}
</script>
<style lang="scss">
</style>
Vuex
./router/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
name: '柏竹'
}
})
Router
./store/index.js
import { createRouter, createWebHistory } from 'vue-router'
// 假设引入的 One组件/Two组件
import One from '../components/One'
import Two from '../components/Two'
const routes = [
{ path: '/one', name: 'one', component: One },
{ path: '/two', name: 'two', component: Two }
]
const router = createRouter({
// 使路由切换产生web页面历史记录
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
版本3应用示例
示例应用应用前把
src/public文件夹的子文件清空(并非清空文件夹)
./public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webapp</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
./src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import store from './store/index'
import router from './router/index'
createApp(App)
.use(store)
.use(router)
.mount('#app')
./src/App.vue
<template>
<div>
<h2>Vuex应用测试</h2>
<p>我是App组件{{ msg }}</p>
<button @click="say">sayLog</button>
<br>
<button @click="getName">App=>getName</button>
<h2>路由组件展示</h2>
<router-link to="/one">Go to One</router-link>
<br>
<router-link to="/two">Go to Two</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
msg: '12'
}
},
methods: {
say () {
console.log('App组件:我太难了')
},
getName () {
console.log(this.$store)
console.log(this.$store.state.name)
}
}
}
</script>
<style scoped>
p {
color: red;
}
</style>
./src/store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
name: '柏竹'
}
})
模板
./src/components/One.vue
<template>
<div>
<p>我是One组件</p>
<button @click="getName">One=>getName</button>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'One',
methods: {
getName () {
console.log(this.$store.state.name)
}
}
}
</script>
<style scoped>
p{
background: red;
}
</style>
./src/components/Two.vue
<template>
<div>
<p>我是Two组件</p>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'Two'
}
</script>
<style scoped>
p{
background: blue;
}
</style>
./src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import One from '../components/One'
import Two from '../components/Two'
const routes = [
{ path: '/one', name: 'one', component: One },
{ path: '/two', name: 'two', component: Two }
]
const router = createRouter({
// 使路由切换产生web页面历史记录
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
呈现方式自行测试
问题
-
项目编辑验证不规范异常问题 **解决方案:**手动配置,在IDEA配置 搜索
ESLint,执行以下操作项- 选中 自动ESLint配置
- 打钩 运行时 ==eslint --fix== 并配置 保存时操作 ==自动ESLint配置==
-
项目首次 ==new Vue({})== 指定无效问题 (有两种解决方案)
-
解决方案:(Vue-Cli3版本以下可解决 为代码添加以下注解 跳过检查
import Vue from 'vue' import App from './App.vue' /* eslint-disable no-new */ new Vue({ el: '#app', render: h => h(App) })3以上的版本 ,因为 new实例的组件未使用因此报错 不允许在赋值/比较之外使用 new实例操作
-
解决方案:(Vue-Cli3版本以上的 指定创建组件应用
import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app')
-
风格指南
必要的
必要的规则会帮你规避错误,所以学习并接受它们带来的全部代价吧
组件命名
组件命名是尽可能以多个单词为组件的名称,至少两个以上
反例:One、todo、Todo
好例:no-one、NoOne、todo-item、TodoItem
data选项
组件中的 data选项 必须是以函数形式返回
组件data如果没有使用函数返回,那么可能会出现数据跨组件的现象
export default {
data () {
return {
foo: 'bar'
}
}
}
Prop选项
组件中 Prop选项 定义尽可能详细看,至少指定传递数据的类型
**好处:**在开发环境下,可避免Vue提示出的警告
反例:
props: ['status']
好例:
props: {
status: String
}
v-for指令
v-for的使用总要伴随 key 的使用,主要避免遍历的 DOM模型 相同的情况
v-for/v-if指令
永远不要同时使用 v-for 和 v-if 的指令
建议方案:
- 使用 计算属性 进行替换列表 进行过滤列表
- 如果指定的是 列表容器 ,那么将
v-if移至 列表容器 上
反例:
<!-- 指定 li 列表的遍历条例 展示
users(Array):用户数据集
user.isActive(boolean):指定用户是否显示
-->
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
<!-- 指定 li 列表 展示
shouldShowUsers(boolean):
-->
<ul>
<li
v-for="user in users"
v-if="shouldShowUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
好例:
<!-- activeUsers : 计算属性 -->
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
...
'activeUsers':{
return this.users.filter((user)=>{
return user.isActive
})
}
<!-- 实例2 -->
<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
组件样式作用域
在组件中的 样式设置 默认是全局的,全局的情况会导致 其他组件 样式也会受到影响
在 style标签 中添加 scoped属性 进行限制作用域(仅限于自身组件
私有 函数名
组件暴露出去后,当中的方法如果和公开的API函数名称冲突,为了避免该问题的出现,建议使用:$_ 作为前缀
反例: update、update、$update
好例:
// 示例1
var myGreatMixin = {
// ...
methods: {
$_myGreatMixin_update: function () {
// ...
}
}
}
// 示例2 (更好的
var myGreatMixin = {
// ...
methods: {
publicMethod() {
// ...
myPrivateFunction()
}
}
}
function myPrivateFunction() {
// ...
}
export default myGreatMixin
强烈推荐
推荐
慎用
Vue案例
代码自行复制应用
商品购物列表
- DOM操作实现功能
- 应用插件:moment插件
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
#app {
width: 600px;
margin: 10px auto;
}
.tb {
border-collapse: collapse;
width: 100%;
}
.tb th {
background-color: #0094ff;
color: white;
}
.tb td,
.tb th {
padding: 5px;
border: 1px solid black;
text-align: center;
}
.add {
padding: 5px;
border: 1px solid black;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div id="app">
<div class="add">
品牌名称:
<input type="text" v-model="name">
<button :disabled="name.length===0" @click="addItem">添加</button>
</div>
<div class="add">
品牌名称:
<input type="text" placeholder="请输入搜索条件" v-model="searchVal">
</div>
<div>
<table class="tb">
<tr>
<th>编号</th>
<th>品牌名称</th>
<th>创立时间</th>
<th>操作</th>
</tr>
<tr v-for="(item,index) in newList" :key="index">
<td>{{index+1}}</td>
<td>{{item.name}}</td>
<td>{{formatDate(item.date)}}</td>
<td>
<a href="#" @click="delItem(index)">删除</a>
</td>
</tr>
<tr v-if="newList.length === 0">
<td colspan="4">没有品牌数据</td>
</tr>
</table>
</div>
</div>
<script src="./vue.js"></script>
<script src="http://cdn.staticfile.org/moment.js/2.24.0/moment.js"></script>
<script>
// 准备数据
let vm = new Vue({
el: "#app",
data: {
list: [
{name: "张三", date: new Date},
{name: "李四", date: new Date},
{name: "王五", date: new Date},
{name: "赵六", date: new Date}
],
// 存储用户输入的数据
name: '',
isShow: false,
searchVal:''
},
methods: {
addItem() {
//添加
for (let item of this.list) {
if (item.name == this.name) {
alert("不能重复");
return;
}
}
this.list.push({name: this.name, date: new Date});
this.name = '';
},
delItem(index) {
if (confirm("是否删除 " + this.list[index].name)) {
this.list.splice(index, 1);
}
},
formatDate(date){
return moment(date).format("YYYY-MM-DD HH:mm:ss");
}
},
computed: {
newList: function () {
return this.list.filter((v) => {
// startsWith()
return v.name.startsWith(this.searchVal);
});
}
}
});
</script>
</body>
</html>
用户列表
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
#app {
width: 600px;
margin: 10px auto;
}
.tb {
border-collapse: collapse;
width: 100%;
}
.tb th {
background-color: #0094ff;
color: white;
}
.tb td,
.tb th {
padding: 5px;
border: 1px solid black;
text-align: center;
}
.add {
padding: 5px;
border: 1px solid black;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div id="app">
<div class="add">
Name:
<input type="text" v-model="name">
<button :disabled="name.length===0" @click="addItem">添加</button>
</div>
<div class="add">
FindName:
<input type="text" placeholder="findName" v-model="searchVal">
</div>
<div>
<table class="tb">
<tr>
<th>Number</th>
<th>ID</th>
<th>Name</th>
<th>Date</th>
<th>Exe</th>
</tr>
<tr v-for="(item,index) in newList":key="item.id">
<td>{{index+1}}</td>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{formatDate(item.date)}}</td>
<td>
<a href="#" @click="delItem(item.id)">删除</a>
</td>
</tr>
<tr v-if="newList.length === 0">
<td colspan="5">没有数据</td>
</tr>
</table>
</div>
</div>
<script src="./vue.js"></script>
<script src="http://cdn.staticfile.org/moment.js/2.24.0/moment.js"></script>
<script src="https://unpkg.com/axios@0.26.1/dist/axios.js"></script>
<script>
// 准备数据
let vm = new Vue({
el: "#app",
data: {
list: [],
// 存储用户输入的数据
name: '',
searchVal: '',
size: 0
},
methods: {
addItem() { // 添加
let node = this.list.find((v) => {
return v.name === this.name;
});
if (node != null) {
alert("不能重复");
return;
}
axios.post('http://localhost:3000/brands',
{id:this.size,name: this.name, date: new Date}).then((res)=>{
console.log("add:Yes")
this.loadDate()
this.name = '';
}).catch((err)=>{
console.log("add:No")
console.log(this.size)
console.log(this.name)
this.name = '';
});
},
delItem(id) { // 删除
if (confirm("确认删除["+id+"]?")) {
axios.delete('http://localhost:3000/brands/' + id).then((res) => {
console.log("del:Yes")
this.loadDate()
}).cache((err) => {
console.log("del:No")
});
}
},
formatDate(date) { // 格式化日期
return moment(date).format("YYYY-MM-DD HH:mm:ss");
},
loadDate(){ //数据加载
console.log("loadDate...")
axios.get("http://localhost:3000/brands").then((res) => {
this.list = res.data;
this.size = this.list.length + 1;
// console.log(res.data)
}).catch((err) => {
console.log(err)
});
}
},
mounted(){ // 首次加载执行
this.loadDate();
},
computed: {
// 新表
newList: function () {
if (this.list.length === 0) return [];
if (this.searchVal === '') return this.list;
return this.list.filter((v) => {
return v.name.startsWith(this.searchVal);
});
}
}
});
</script>
</body>
</html>
react