admin 管理员组文章数量: 887017
"对A,我还剩一张牌啦!"
"呃。。。要不起
这俩天被洗脑了,看了好几个主播的“鸭鹅杀”。脑子里总是那一句:“叼得一发言:叼的一认为.....,对是不对”
Vue CLI
npm config set registry https://registry.npm.taobao --global
CLI (@vue/cli
) 是一个全局安装的 npm 包,提供了终端里的 vue
命令。它可以通过 vue create
快速搭建一个新项目,或者直接通过 vue serve
构建新想法的原型。你也可以通过 vue ui
通过一套图形化界面管理你的所有项目。
1.安装vue cli
在这之前,确保安装了Node(推荐 v10 以上)
npm install -g @vue/cli
下载太慢,可以先设置镜像
npm config set registry https://registry.npm.taobao --global
验证它是否安装成功
vue --version
如下:则安装成功
怎样查看vue-cli的安装路径
where vue
如果没有配置npm的下载路径,那么vue就会被下载到系统用户目录下
卸载vue-cli
npm uninstall vue-cli -g
结果呢,还是
1. 删除缓存
到系统盘的用户目录下有个Appdata,然后有个Roaming(缓存)如图:
2.删除环境变量
进入控制面板(我的是win10系统),点击此电脑——》系统属性——》在左边的输入框输入“高级系统”,点击“查看高级系统设置”——》选择环境变量——》用户变量和系统变量中找到“path”变量,点进去,找到“node”相关的,删掉
找到安装路径,有个卸载文件,点击就能卸载了
如果按装没有成功需要检查nodejs和NPM的版本,通过 node -v 和npm -v检查
2.创建项目
vue create 项目名
vue create vue-xiaoyumao
选择vue2 ,回车,完成后就会在桌面生成一个文件夹
3.目录结构分析
使用VsCode打开
main.js 是 npm run serve 的开端
main.js是入口文件,一般不需要改
import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false new Vue({ render: h => h(App), }).$mount('#app')
每个 Vue 应用都需要通过实例化 Vue 来实现。
index.html
<!DOCTYPE html> <html lang=""> <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"> <!--配置页签图标--> <link rel="icon" href="<%= BASE_URL %>favicon.ico"> <!--配置网页标题--> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> <!--当浏览器不支持js时noscript中的元素就会被渲染 --> <noscript> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <!--容器--> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
package.json
package.json 是前端每个项目都有的 json 文件,位于项目的根目录。package.json 里面有许许多多的配置,介绍一些常见配置,我把它们分为了 7 大类:
- 描述配置
主要是项目的基本信息,包括名称,版本
- 文件配置
包括项目所包含的文件,以及入口等信息。
- 脚本配置
指定项目的一些内置脚本命令,这些命令可以通过 npm run 来执行。通常包含项目开发,构建 等 CI 命令,
- 依赖配置
- 发布配置
- 系统配置
- 第三方配置
4.npm run serve
进到项目目录,cmd打开终端,执行命令npm run serve 启动项目
补充:npm run build 命令会生成最纯粹的js,css,html
浏览器访问效果:localhost:8080
5.自定义端口
默认的项目启动后访问localhost:8080
在vue.config.js文件里配置就行
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false, // 关闭语法检查 防止不必要的语法报错
// 配置devServer
devServer: {
host: 'localhost', // 项目运行的ip
port: 8000, // 项目运行的端口号
}
})
重启项目
但是会引起跨域的问题。
加链接头,开启跨域,加/api作为识别。意为请求/api下的链接,直接回转到target
pathRewrite:重写路径 后端识别时候把/api替换成空
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false, // 关闭语法检查 防止不必要的语法报错
devServer: {
host: 'localhost', // 项目运行的ip
port: 8000, // 项目运行的端口号
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'/api': ''
}
}
}
}
})
6.自定义界面
接下来换成我们自己写的组件进行渲染
新建pages目录,下面建2个.vue文件
新增Bedroom.vue
<template> <div> <p>{{ msg }}</p> </div> </template> <script> export default { // eslint-disable-next-line vue/multi-word-component-names name: "Bedroom", data() { return { msg: "欢迎来到卧室:你要睡觉吗", }; }, }; </script>
新增Kitchen.vue
<template> <div> <p>{{ msg }}</p> </div> </template> <script> export default { // eslint-disable-next-line vue/multi-word-component-names name: "Kitchen", data() { return { msg: '欢迎来到厨房:你要做饭吗', }; }, }; </script>
修改App.vue,引入我们自定义的2个组件并注册使用。如下:
<template> <div id="app"> <Bedroom /> <Kitchen /> </div> </template> <script> import Bedroom from "./pages/Bedroom.vue"; import Kitchen from "./pages/Kitchen.vue"; export default { name: "App", components: { Bedroom, Kitchen, }, }; </script>
页面打开后,渲染效果如下:
组件component
1、组件概念
每个 .vue 组件都由 3 部分构成,分别是:
- template -> 组件的模板结构
- script -> 组件的 JavaScript 行为
- style -> 组件的样式
其中,每个组件中必须包含 template 模板结构,而 script 行为和 style 样式是可选的组成部分。vue 规定:每个组件对应的模板结构,需要定义到 <template> 节点中。
<template> 是 vue 提供的容器标签,只起到包裹性质的作用,它不会被渲染为真正的 DOM 元素。
vue 2.x中,template节点内的所有元素,最外层“必须有”唯一的根节点进行包裹,否则报错
<template> <div> <p>{{ msg }}</p> </div> </template>
<script> 节点
vue 规定:组件内的 <script> 节点是可选的,开发者可以在 < script> 节点中封装组件的 JavaScript 业务逻辑。< script > 节点的基本结构如下
<script> //今后,组件相关的data数据、methods方法等,都需要定义到export default所导出的对象中。 export default {} </script>
可以通过name属性当前组件定义一个名称(建议:每个单词的首字母大写)代码如下:
<script> export default { // name属性指向的是当前组件的名称(建议:每个单词的首字母大写) name: 'MyApp' } </script>
data属性
vue 组件渲染期间需要用到的数据,可以定义在 data 节点中:
<script> export default { // 组件的名称 name: 'MyApp', // 组件的数据(data方法中return出去的对象,就是当前组件渲染期间需要用到的数据对象) data() { return { username: '哇哈哈', } }, } </script>
其中组件中的 data 必须是函数
组件内的 <style> 节点
vue 规定:组件内的 <style> 节点是可选的,开发者可以在 <style> 节点中编写样式美化当前组件的 UI 结构。<script > 节点的基本结构如下:
2、组件导入
第一种
自然是直接import xxx from "组件的路径",然后再到components中引用,例如vue自带的helloworld.vue示例:
import Kitchen from "@/pages/Kitchen.vue";
第二种
在原本的组件目录文件夹中添加一个index.js,
然后在这个index.js中将这些组件导出,
export { default as Kitchen } from "./Kitchen"; export { default as Bedroom } from "./Bedroom"; export { default as HelloWorld } from "./HelloWorld";
在用到这些组件的时候就可以直接在导入这个index.js时解构获取想要的组件了,如下
注意,解构时的名字必须跟你导出的的一致,要用哪些就导入哪些组件。
3、组件嵌套
在单文件组件Bedroom.vue种引入BedsideCupboard组件并和SingleBed组件使用:
<template>
<div>
<BedsideCupboard />
<SingleBed />
</div>
</template>
<script>
import BedsideCupboard from "./BedsideCupboard.vue";
import SingleBed from "./SingleBed.vue";
export default {
components: { BedsideCupboard, SingleBed },
name: "Bedroom",
data() {
return {
msg: "欢迎来到卧室:你要睡觉吗",
};
},
};
</script>
打开vue开发者工具,直观效果"组件嵌套"
看得出来,VM非常省心,只管理App组件(约定)
<template>
<div id="app">
<div>
<Bedroom />
</div>
</div>
</template>
<script>
import { Kitchen, Bedroom } from "@/pages";
export default {
name: "App",
components: { Kitchen, Bedroom },
};
</script>
4、组件实例对象
VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
Vue的实例对象,以后简称vm。
组件本质
1、Bedroom组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
2、我们只需要写<Bedroom/>或<Bedroom></Bedroom>,Vue解析时会帮我们创建Bedroom组件的实例对象,即Vue帮我们执行的:new VueComponent(options).3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
关于this指向:
(1)组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数它们的this均是vc【VueComponent实例对象】
(2)new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数它们的this均是【Vue实例对象】
vm管理着vc
vm能通过el决定为哪个容器服务,vc不行,只能跟着大哥vm混
vc中,data必须是一个函数,vm中可以是data函数也可以是data对象
组件通信
1、父传子props
让组件接收外部传过来的数据
接收数据:
第一种方式(只接收):props:['name']
第二种方式(限制数据类型):props:{name:String}
第三种方式(限制类型、限制必要性、指定默认值):
props:{
name:{
type:String, //类型
required:true, //必要性
default:'JOJO' //默认值
}
}
2、子传父this.$emit
触发自定义事件:this.$emit('atguigu',数据)
自定义事件是给组件使用的
由于是在<Student>标签绑定了自定义事件,要触发就找student组件。事件触发后回调用methods里的demo()方法.
//父组件中使用子组件标签 <Student v-on:atguigu='demo'> <Student @atguigu='demo'> //子组件触发父组件中demo方法 demo(){ console.log("demo被调用了") } //子组件触发时携带参数 demo(name){ console.log('demo被调用了',name) //atguigu事件触发后的回调 }
那么来看看在子组件:student组件是如何触发父组件里自定义事件atguigu
<button @click="sendStudentName" >把学生名给app</button> sendStudentName(){ this.$emit('atguigu') //在组件触发自定义事件atguigu //也可以带参传值 //this.$emit('atguigu',"我是子组件传给父组件的值") }
3、事件总线 EventBus
vue事件总线就像所有组件的事件中心,在组件中,我们可以使用 $emit
,$on
,$off
分别来分发、监听、取消监听事件。
将其定义在 main.js 文件中,创建在 vm 的实例对象身上,因为 vm 实例对象只有一个
//创建vm new Vue({ el:'#app', render: h => h(App), // beforeCreate中模板未解析,且this是vm beforeCreate(){ Vue.prototype.$bus = this //安装全局事件总线 } })
我们可以在某个Vue页面使用。
methods:{
// 触发事件,事件名不能重复
aaa(){
this.$bus.$emit('updateMessage', '德华');
}
},
另一个Vue页面使用
this.$bus.$on('updateMessage', function(value) {
console.log(value);
})
同时也可以使用this.$bus.$off('sendMsg')
来移除事件监听
4、this.$refs
应用在html标签上获取的是真实DOM元素,应用在组件标签上获取的是组件实例对象(vc)
使用方式:
打标识:<h1 ref="xxx"></h1> 或 <School ref="xxx"></School>
获取:this.$refs.xxx
SlOT插槽
1、默认插槽
先弄一个基本效果
创建Category.vue
<template> <div class="category"> <h3>{{title}}分类</h3> <ul> <li v-for="(item,index) in listData" :key="index">{{item}}</li> </ul> </div> </template> <script> export default { name: "Category", props:['listData','title'] }; </script> <style> .category { background-color: aqua; width: 200px; height: 300px; } h3{ text-align: center; background-color: burlywood; } </style>
在App.vue中引入并使用Category.vue
<template> <div id="app" class="container"> <Category title="中立阵营" :listData="zhongli" /> <Category title="好人阵营" :listData="haoren" /> <Category title="狼人阵营" :listData="lang" /> </div> </template> <script> import Category from "./components/Category.vue"; export default { name: "App", components: { Category, }, data() { return { zhongli: ["呆呆鸟", "猎鹰", "秃鹫", "鸽子", "鹈鹕"], haoren: [ "加拿大鹅", "观鸟者", "鹅", "网红", "星界", "警长", "正义使者", "模仿", "侦探", "通灵", ], lang: [ "刺客", "间谍", "食鸟鸭", "专业杀手", "承办丧葬者", "身份窃贼", "忍者", "爆炸王", ], }; }, }; </script> <style > .container { display: flex; justify-content: space-around; } </style>
页面效果:
接着我们开始引入插槽
在Category.vue中做改变,加<slot>标签
<template> <div class="category"> <h3>{{title}}分类</h3> <!-- 定义一个插槽,等别的组件填充 --> <slot>我是插槽的默认值,当没有传递具体结构,我会出现</slot> </div> </template> <script> export default { name: "Category", props:['title'] }; </script> <style> .category { background-color: aqua; width: 200px; height: 300px; } h3{ text-align: center; background-color: burlywood; } </style>
在App.vue中使用<Category>时给插槽传入具体的结构和数据
<template> <div id="app" class="container"> <Category title="中立阵营" :listData="zhongli"> <img src="./static/image/zhongli.jpg" /> </Category> <Category title="好人阵营" :listData="haoren"> <ul> <li v-for="(item, index) in haoren" :key="index">{{ item }}</li> </ul> </Category> <Category title="狼人阵营" :listData="lang"> <img src="./static/image/lang.jpg" /> </Category> </div> </template> <script> import Category from "./components/Category.vue"; export default { name: "App", components: { Category, }, data() { return { zhongli: ["呆呆鸟", "猎鹰", "秃鹫", "鸽子", "鹈鹕"], haoren: [ "加拿大鹅", "观鸟者", "鹅", "网红", "星界", "警长", "正义使者", "模仿", "侦探", "通灵", ], lang: [ "刺客", "间谍", "食鸟鸭", "专业杀手", "承办丧葬者", "身份窃贼", "忍者", "爆炸王", ], }; }, }; </script> <style > .container { display: flex; justify-content: space-around; } img{ width:100% } </style>
页面效果:
2、具名插槽
在Category.vue中做改变,name属性给插槽起名字
<template> <div class="category"> <h3>{{title}}分类</h3> <!-- 定义一个插槽,等别的组件填充 --> <slot name="center">我是插槽的默认值,当没有传递具体结构,我会出现1</slot> <slot name="footer">我是插槽的默认值,当没有传递具体结构,我会出现2</slot> </div> </template>
在App.vue中,slot属性指定填充哪个插槽
<template> <div id="app" class="container"> <Category title="中立阵营" :listData="zhongli"> <img slot="center" src="./static/image/zhongli.jpg" /> <a slot="footer" href="">点我查看更多</a> </Category> <Category title="好人阵营" :listData="haoren"> <ul slot="center"> <li v-for="(item, index) in haoren" :key="index">{{ item }}</li> </ul> <div slot="footer"> <a href="">好人阵营</a> <h2>欢迎加入好人阵营</h2> </div> </Category> <Category title="狼人阵营" :listData="lang"> <img slot="center" src="./static/image/lang.jpg" /> <template slot="footer"> <a href="">狼人阵营</a> <h4>欢迎来到我们狼人阵营</h4> </template> </Category> </div> </template>
效果如下:
如果使用template包裹,可以有新的写法
<!-- 旧的写法如下 --> <Category title="狼人阵营" :listData="lang"> <img slot="center" src="./static/image/lang.jpg" /> <template slot="footer"> <a href="">狼人阵营</a> <h4>欢迎来到我们狼人阵营</h4> </template> </Category>
新的写法:注意v-slot只能写在组件的<template>
<Category title="狼人阵营" :listData="lang"> <img slot="center" src="./static/image/lang.jpg" /> <template v-slot:footer> <a href="">狼人阵营</a> <h4>欢迎来到我们狼人阵营</h4> </template> </Category>
区别:
3、作用域插槽
数据和结构不在一块
数据放在Category.vue中
<template> <div class="category"> <h3>{{title}}</h3> <!-- 定义一个插槽,等别的组件填充 sanxianshen会传给插槽的使用者--> <slot :sanxianshen="sanxianshen">我是插槽的默认内容</slot> </div> </template> <script> export default { name: "Category", props:['title'], data(){ return{ sanxianshen: ["大天湿婆", "梵天", "毗湿奴"] } } }; </script> <style> .category { background-color: aqua; width: 200px; height: 300px; } h3{ text-align: center; background-color: burlywood; } </style>
在App.vue中接收到插槽传上来的数据。使用template包裹并且使用scope属性
<template> <div id="app" class="container"> <Category title="印度三相神"> <!-- 必须要用template包裹才能拿到插槽给的数据 --> <template scope="India"> {{India}} </template> </Category> </div> </template> <script> import Category from "./components/Category.vue"; export default { name: "App", components: { Category, }, data() { return {} }, }; </script> <style > .container { display: flex; justify-content: space-around; } img { width: 100%; } </style>
页面效果:
在App.vue中展示数据的时候,使用不同的样式展示(无序列表,有序列表,p标签)
<template> <div id="app" class="container"> <Category title="印度三相神"> <!-- 必须要用template包裹才能拿到插槽给的数据 --> <template scope="India"> <ul> <li v-for="(item, index) in India.sanxianshen" :key="index">{{ item }}</li> </ul> </template> </Category> <Category title="印度三相神"> <template scope="India"> <ol> <li v-for="(item, index) in India.sanxianshen" :key="index">{{ item }}</li> </ol> </template> </Category> <Category title="印度三相神"> <template scope="India"> <p v-for="(item, index) in India.sanxianshen" :key="index">{{ item }}</p> </template> </Category> </div> </template>
当然还可以使用ES6的解构赋值,看起来更好看
<template>
<div id="app" class="container">
<Category title="印度三相神">
<!-- ES6解构赋值 -->
<template scope="{sanxianshen}">
<ul>
<li v-for="(item, index) in sanxianshen" :key="index">{{ item }}</li>
</ul>
</template>
</Category>
<!-- 使用slot-scope,是新的api -->
<Category title="印度三相神">
<template slot-scope="{sanxianshen}">
<ol>
<li v-for="(item, index) in sanxianshen" :key="index">{{ item }}</li>
</ol>
</template>
</Category>
</div>
</template>
路由Vue Router
1、使用路由后有哪些变化
路由route是一组key-value的对应关系;多个路由需要经过路由器的管理
对应在vue中就是 路径与组件的映射成为路由
路由器router时时刻刻检测路径变化
vue-router是vue的一个插件库,专门用来实现spa应用(单页面web应用),即整个页面只有一个完成的页面。
vue-router相比之前的多页面(多个html)的区别
1.点击页面中的导航链接不会刷新页面
2.做页面的局部更新,数据需要通过ajax请求获取
2、引入路由器
npm install vue-router --save
后续可能会报错:vue_router__WEBPACK_IMPORTED_MODULE_2__.default is not a constructor
解决办法:卸载原本的vue-router,指定安装版本
npm uninstall vue-router npm install vue-router@3
router/index.js创建路由器
新建router文件夹
在index.js中写入如下内容
配置路由规则并创建路由实例
每个路由规则都是一个配置对象、其中至少包含path和component俩个属性
- path表示 路由匹配的hash地址
- component表示路由规则对应要展示的组件对象
//该文件专门用于创建整个应用的路由器 import VueRouter from "vue-router"; import Bedroom from "@/pages/Bedroom.vue"; import Kitchen from "@/pages/Kitchen.vue"; //创建并暴露一个路由器 export default new VueRouter({ routes: [ { path: "/bedroom", component: Bedroom, }, { path: "/kitchen", component: Kitchen, }, ], });
main.js配置路由器
在main.js中添加内容如下
//引入Vue import Vue from 'vue' //引入App import App from './App.vue' //引入VueRouter import VueRouter from 'vue-router' //引入路由器 import router from './router' //关闭vue的生产提示 Vue.config.productionTip = false //应用插件 Vue.use(VueRouter); new Vue({ router:router, render: h => h(App), }).$mount('#app')
为了能够让路由规则生效,必须把路由对象挂载到vue实例对象上
3、<router-link>声明式
router-link实现点击不同的导航,路径发生变化
<router-link>:该标签是一个vue-router中已经内置的组件,他会被渲染成一个<a>标签。
router-link属性介绍 to:用于指定跳转的路径,to属性的值会被渲染为#开头的hash地址 tag:tag可以指定<router-link>之后渲染成什么组件,比如我们下面的代码会被渲染成一个<li>元素,而不是<a> 。 <router-link to='/home' tag='li'>
<router-view>:该标签会根据当前的路径,动态渲染出不同的组件。
通过路由规则匹配到的组件,将会被渲染到<router-view>所在的位置
在App.vue中,修改为如下内容
<template> <div id="app"> <div> <!--vue中借助router-link 实现路由的切换 --> <router-link to="/bedroom">卧室</router-link> <br /> <router-link to="/kitchen">厨房</router-link> <!--路由匹配到的组件将渲染在这里--> <router-view></router-view> </div> </div> </template> <script> export default { name: "App", components: {}, }; </script>
页面效果:点击卧室
页面效果:点击厨房
4、router.push
编程式
点击 <router-link :to="...">
等同于调用 router.push(...)
。
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path
,params
会被忽略,上述例子中的 query
并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name
或手写完整的带有参数的 path
:
this.$router.push({
})
this.$router.replace({
})
this.$router.forward()//前进
this.$router.back()//后退
this.$router.go()
router.replace
跟 router.push
不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
路由缓存
路由切走之后,再切回来。数据就没了,因为组件会销毁和重新挂载
5、$route
//$router : 是路由操作对象,只写对象
//$route : 路由信息对象,只读对象
//操作 路由跳转
this.$router.push({
name:'hello',
params:{
name:'word',
age:'11'
}
})
params是路由的一部分,必须要在路由后面添加参数名。query是拼接在url后面的参数,没有也没关系
- 传参可以使用params和query两种方式。
6、路由传参params和query
使用params传参只能用name来引入路由,即push里面只能是name:’xxxx’,不能是path:’/xxx’
1.params
传参(显示参数)
{ path: '/child/:id', component: Child }
this.$router.push({ path:'/child/${id}', })
接收:
this.$route.params.id
2. params
传参(不显示参数)
通过路由的别名 name 进行传值的
{ path: '/child, name: 'Child', component: Child }
this.$router.push({ name:'Child', params:{ id:1 } })
接收:
this.$route.params.id
query
传参(显示参数)
需要子路由提前配置好路由别名(name 属性)
{ path: '/child, name: 'Child', component: Child }
this.$router.push({ name:'Child', query:{ id:1 } })
接收:
this.$route.query.id
7、路由器的2种工作模式
前端路由是基于hash值的变化进行实现的(比如点击页面中的菜单或者按钮改变URL的hash值,根据hash值的变化来控制组件的切换)
hash模式
路由器的默认工作模式是hash
1.对于一个url来说,什么是hash值?#及其后面的内容就是hash值。
2.hash值不会包含在HTTP请求中,即:hash值不会随着http请求发给服务器。3.hash模式
1.地址中永远带着#号,不美观。 2.若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。 3.兼容性较好
history模式
1.地址干净,美观。
2.兼容性和hash模式相比略差。
3.应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
8、嵌套路由
创建一个主路由
在src/router/index.js中配置嵌套路由,在Main.vue中设置子路由出口
const routes = [
// 配置主路由
{
// 外层路由
path:'/',
component:Main,
children:[
// 嵌套路由/子路由:它们的路由出口在Main.vue中
{ path: 'home', component: Home },
{ path: 'user', component: User }
]
}
]
9、路由重定向
路由重定向指的是:
- 用户在访问地址 A 的时候,强制用户跳转到地址 C ,从而展示特定的组件页面;
- 通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向:
var myRouter = new VueRouter({
//routes是路由规则数组
routes: [
//path设置为/表示页面最初始的地址 / ,redirect表示要被重定向的新地址,设置为一个路由即可
{ path:"/",redirect:"/user"},
{ path: "/user", component: User },
{ path: "/login", component: Login }
]
})
10、动态匹配路由
var User = { template:"<div>用户:{{$route.params.id}}</div>"}
var myRouter = new VueRouter({
//routes是路由规则数组
routes: [
//通过/:参数名 的形式传递参数
{ path: "/user/:id", component: User },
]
})
VueX 多组件共享数据
1、纯vue版实现求和案例
创建组件Count.vue
<template> <div> <h1>当前求和为:{{ sum }}</h1> <select v-model.number="n"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button @click="increment">+</button> <button @click="decrement">-</button> <button @click="incrementOdd">当前求和为奇数再加</button> <button @click="incrementWait">等一等再加</button> </div> </template> <script> export default { name: "Count", data() { return { n: 1, //用户选择的数字 sum: 0, //当前的和 }; }, methods: { increment() { this.sum+=this.n }, decrement() { this.sum-=this.n }, incrementOdd() { if(this.sum%2){ this.sum+=this.n } }, incrementWait() { setTimeout(() => { this.sum+=this.n }, 500); }, }, }; </script> <style> button { margin-left: 5px; } </style>
在App.vue中引入Count.vue
<template> <div id="app"> <count /> </div> </template> <script> import Count from "./components/Count.vue"; export default { name: "App", components: { Count, }, }; </script>
页面效果:
说实话,我写完觉得也没啥大的毛病啊,看看vuex能做什么优化呢
2、Vuex工作原理图
Vuex 是专门为 Vue.js 设计的状态管理库,它采用集中式存储管理应用的所有组件的状态。
我们常说的状态管理,往往是指外部管理,目的是对状态和组件进行分离,具体到 Vuex 里的表现就是:把应用的所有组件的状态抽取出来,以一个全局单例模式在应用外部采用集中式存储管理
工作对象
state:状态,用于存储对象数据
Actions:行为,用于保存方法的行为,可以包含异步操作
Mutations:转变,用于提交行为的结果,不可以包含异步操作
Getters:类似于在store中的计算属性
Modules:模块,将store分割成不同的模块,每个模块有自己的state、actions、mutationsstore.dispatch storemit state、Actions、Mutations这三个都要经过store管理
工作原理
Render:vue组件中可以读取state中的数据(对应工作原理图中的①这一条线)
Dispatch:调用store中的dispatch方法,由vue组件派发给Actions执行,Actions可以继续给自身派发,也可以调用异步方法(Backend API)(对应工作原理图中的②这一条线)
Commit:调用store中的commit方法,由Actions提交给Mutations执行,也可以直接由组件提交(对应工作原理图中的③⑤这两条线)
Mutate:Actions、Mutations中更改state中的数据,不需要手动执行,由api直接调用。一般是Mutations调用,在此处调用,可以被开发者工具(Devtools)直接监控,由Actions调用时,不被监控。(对应工作原理图中的④⑥这两条线)
3、创建并引入store
因为我们使用的是vue2,对应就要安装vuex3
npm i vuex@3
创建store目录,并在其下创建index.js
index.js文件内容如下
import Vue from 'vue' //引入Vuex import Vuex from 'vuex' //使用插件 Vue.use(Vuex) //准备actions,用于响应组件中的动作 const actions={} //准备mutations,用于操作数据 const mutations={} //准备state,用于存储数据 const state={} //创建并暴露store export default new Vuex.Store({ actions, mutations, state })
============
在main.js引入vuex插件,并在创建vm时传入store
import Vue from 'vue' import App from './App.vue' //引入store import store from './store' //关闭vue的生产提示 Vue.config.productionTip = false //创建vm const vm=new Vue({ store, render: h => h(App), }).$mount('#app') console.log(vm)
打开控制台就可以看到$store
4、使用Vuex对求和案例改造
改造store目录下的index.js
//该文件用于创建vuex中最为核心的store import Vue from 'vue' //引入Vuex import Vuex from 'vuex' //使用插件 Vue.use(Vuex) //准备actions,用于响应组件中的动作 const actions={ 'jia':function(context,value){ //context上下文对象,可以理解为mini版store console.log('actions中的jia被调用了',context,value) contextmit('JIA',value) }, 'jian':function(context,value){ //context上下文对象,可以理解为mini版store console.log('actions中的jian被调用了',context,value) contextmit('JIAN',value) } } //准备mutations,用于操作数据 const mutations={ 'JIA':function(state,value){ console.log('mutations中的JIA被调用了',state,value) state.sum+=value }, 'JIAN':function(state,value){ console.log('mutations中的JIAN被调用了',state,value) state.sum-=value } } //准备state,用于存储数据 const state={ sum:0 } //创建并暴露store export default new Vuex.Store({ actions, mutations, state })
======改造Conut.vue
<template> <div> <!--模板中可以直接使用vc中的数据,不用写this.--> <h1>当前求和为:{{ $store.state.sum }}</h1> <select v-model.number="n"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button @click="increment">+</button> <button @click="decrement">-</button> <button @click="incrementOdd">当前求和为奇数再加</button> <button @click="incrementWait">等一等再加</button> </div> </template> <script> export default { name: "Count", data() { return { n: 1//用户选择的数字 }; }, methods: { increment() { this.$store.dispatch('jia',this.n) }, decrement() { this.$store.dispatch('jian',this.n) }, incrementOdd() { if(this.$store.state.sum%2){ this.$store.dispatch('jia',this.n) } }, incrementWait() { setTimeout(() => { this.$store.dispatch('jia',this.n) }, 500); }, }, }; </script> <style> button { margin-left: 5px; } </style>
此时效果就和原来的一样了,每个按钮都生效
可以做优化,没有业务逻辑可以跳过actions,在组件里使用commit方法而不是dispatch。
5、store中的getters配置项
当state中的数据需要经过加工后再使用,可以使用getters加工(适合逻辑复杂并需要被复用)
getters配置项
在Count.vue中使用
<h1>当前求和为:{{ $store.state.sum }}</h1> <h1>当前求和放大10倍为:{{ $store.getters.bigSum }}</h1>
vue的ajax
1.vue的ajax
npm install axios
安装其他插件的时候,可以直接在 main.js 中引入并使用 Vue.use()来注册,但是 axios并不是vue插件,所以不能 使用Vue.use(),所以只能在每个需要发送请求的组件中即时引入。
怎么解决呢?在main.js中引用axios
import axios from 'axios';
Vue.prototype.$axios = axios //全局注册,使用方法为:this.$axios
执行 GET 请求
this.$axios
.get("/api/author/list", {
params: {},
})
.then((response) => {
console.log(response.data.data);
this.nameArr = response.data.data;
})
.catch(function (error) {
console.log(error);
});
结果
----------------------
执行 POST 请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
1
2.引入element-ui
npm install element-ui -S
官网:组件 | Element
在main.js入口文件使用element-ui插件
import Vue from 'vue'
import ElementUI from 'element-ui'; // 引入element-ui
import 'element-ui/lib/theme-chalk/index.css'; // element-ui的css样式要单独引入
import App from './App.vue'
Vue.config.productionTip = false
Vue.use(ElementUI); // 这种方式引入了ElementUI中所有的组件
new Vue({
render: h => h(App),
}).$mount('#app')
在APP.vue组件中使用element-ui组件
<template>
<div id="app">
<HelloWorld />
<!--图标-->
<div>
<el-row>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
<el-button type="primary" icon="el-icon-search">搜索</el-button>
</el-row>
</div>
</div>
</template>
效果他不就来了嘛
3.网站部署
nginx是一款轻量级的web服务器,反向代理服务器。
将网站部署到nginx服务器上
vue打包命令,生成dist文件夹
npm run build
上传到服务器的html目录下
修改配置文件nginx.conf
效果:有页面,但是点击后并无数据
1
4.计算属性computed
vue认为data里写的就是属性,计算属性放在computed
计算属性要求把计算的整个过程配置成一个对象
get的return返回值是什么,计算属性的值就是什么
对App.vue做内容修改
<template> <div id="app"> <div> 姓: <input type="text" v-model="firstname" /> <br /> 名: <input type="text" v-model="lastname" /> <br /> 全名: <span>{{ fullname }}</span> </div> </div> </template> <script> export default { name: "App", components: {}, data() { return { firstname: "小", lastname: "羽毛", }; }, computed: { // 是属性fullname通过data里的属性计算出来的 fullname: { get() { console.log('get被调用了'); //此处this是vc return this.firstname + "-" + this.lastname; }, }, }, }; </script>
界面效果:
打开vue开发者工具,就能看到哪些是计算属性了
再看看这个效果,猜猜get被调用了几次,由于computed的缓存机制,get方法只被调用了一次
get方法调用时机总结:
1.初次读取fullname时,get会被调用。
2.所依赖的数据发生变化时,get会被调用。
依赖指的就是它是通过谁计算出来的,它就依赖谁。
set方法是可以不写的,在计算属性发生改变时会调set方法,入参就是改变后的值
computed: { // 是属性fullname通过data里的属性计算出来的 fullname: { get() { console.log('get被调用了'); //此处this是vc return this.firstname + "-" + this.lastname; }, set(value){ //value是改变后的值 console.log('set被调用了',value) const arr=value.split('-') this.firstname=arr[0] this.lastname=arr[1] } }, },
计算属性简写形式如下,
要求只有computed里只有get,没有set修改
原来的计算属性:
简写后
computed: { // 是属性fullname通过data里的属性计算出来的 fullname() { return this.firstname + "-" + this.lastname; }, },
1
部署前后端分离项目
1、npm run build
npm run build
——此命令从 package.json 脚本字段运行构建字段,结果构建出来dist文件夹
dist 文件夹就是我们需要的包,随后放至服务器部署上线即可;需要注意打包之后无论在项目中做了何种修改,都需要 npm run build 重新打包。
2、前后端一起部署
前端打包成静态文件后,拷贝到后端项目中,把静态资源文件放到static目录下。
部署后端项目
使用maven,package打包
打包结果
在命令行窗口运行我们的jar包
java -jar E:\workspace\mybatis-plus\springboot-project\target\spingboot-project-1.0-SNAPSHOT.jar
http://localhost:8080/index.html
3、 Nginx 部署
前端用 Nginx 部署,后端用 Nginx 做代理
版权声明:本文标题:22-12-19 西安 vue-cli vue-cli脚手架、组件化编程、插槽、vue-router路由、Vuex共享数据 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1729002938h1305611.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论