Vue初识系列【2】内容升级版 比眉伴天荒 2024-03-30 15:10 62阅读 0赞 #### 文章目录 #### * 一 模板语法 * * 1.1 文本 * 1.2 原始THTML * 1.3 属性Attribute * 1.4 JavaScript表达式的使用 * 二 条件渲染 * * 2.1 v − i f & v − e l s e v-if\\&v-else v−if&v−else * 2.2 v − s h o w v-show v−show * 2.3 v − i f v-if v−if与 v − s h o w v-show v−show的区别 * 三 列表渲染 * * 3.1 v − f o r v-for v−for列表渲染 * 3.2 v − f o r v-for v−for维护状态 * 四 事件处理 * * 4.1 监听事件 * 4.2 事件处理方法 * 4.3 内联处理器中的方法(事件传递参数) * 4.4 完整代码和效果展示 * 五 表单输入绑定 * * 5.1 v − m o d e l v-model v−model简介 * 5.2 修饰符 * 六 组件基础 * * 6.1 单文本组件 * 6.2 加载组件 * 6.3 组件的组织 * 七 P r o p s Props Props组件交互 * * 7.1 Props简介 * 7.2 演示 * * 7.2.1 App.vue * 7.2.2 MyCompent.vue * 八 自定义事件组件交互 * * 8.1 简介 * 8.2 演示 * * 8.2.1 MyCompent.vue * 8.2.2 App.vue * 九 组件生命周期 * * 9.1 生命周期钩子函数 * 9.2 钩子函数分类 * 9.3 演示 * 十 Vue引入第三方Swiper * * 10.1 Swiper简介 * 10.2 演示 * * 10.2.1 安装Swiper * 10.2.2 引入&使用 * 十一 Axios网络请求 * * 11.1 安装 * 11.2 引入 * 11.3 网络请求演示get&post * 11.4 网络请求封装 * 11.5 演示 * * 11.5.1 request.js * 11.5.2 index.js * 11.5.3 path.js * 11.6 网络请求跨域解决方案 * 十二 Vue引入路由配置 * * 12.1 手动引入步骤 * 12.2 创建项目时引入路由 * 12.3 完整代码 * * 12.3.1 index.js * 12.3.2 HomeView.vue * 12.3.3 AboutView.vue * 12.3.4 main.js * 12.4 路由传递参数 * 12.5 完整代码 * * 12.5.1 index.js * 12.5.2 App.vue * 12.5.3 NewsView.vue * 12.5.4 NewsDetails.vue * 12.6 嵌套路由 * 12.7 完整代码 * * 12.7.1 index.js * 12.7.2 AboutView.vue * 12.7.3 AboutUs.vue * 12.7.4 AboutInfo.vue * 十三 Vue状态管理(Vuex) * * 13.1 Vuex简介 * 13.2 手动引入步骤 * 13.3 创建项目时引入 * 13.4 完整代码 * * 13.4.1 HelloWorld.vue * 13.4.2 index.js * 13.4.3 App.vue * 13.4.4 main.js * 13.5 Vue状态管理核心(Vuex) * * 13.5.1 核心概念简介 * 13.5.2 完整代码演示 ## 一 模板语法 ## ### 1.1 文本 ### - 数据绑定最常见的形式是${ {}}$双括号语法的文本插值。 - 一般配合`JS data()`使用 <span>{ {msg}}</span> <script> export default { name: 'HelloWorld', data() { return { msg: "消息" } } } </script> ![在这里插入图片描述][bef38ba7bd7a4591ba4d0e730fbfee8d.png] ### 1.2 原始THTML ### * 双大括号会将数据解释为普通文本 * 使用 − h t m l -html −html会将文本输出为HTML代码解析后的结果 <h1>{ { rawHtml }}</h1> <h1 v-html="rawHtml"></h1> <script> export default { name: 'HelloWorld', data() { return { rawHtml: '<a herf="htttp://www.baidu.com">百度</a>' } } } </script> ![在这里插入图片描述][a0719d2757974521b0f43a66657bcaea.png] ### 1.3 属性Attribute ### * 使用 v − b i n d v-bind v−bind指令(使用效果同双到括号) <h1 v-bind:id="dynamicId">{ {dynamicId }}</h1> <!--简写:<h1 :id="dynamicId">{ {dynamicId }}</h1>--> <script> export default { name: 'HelloWorld', data() { return { dynamicId: 1001 } } } </script> ![在这里插入图片描述][2ed4f5a75d1d40009bbc27781714c3f0.png] ### 1.4 JavaScript表达式的使用 ### * Vue.js提供了完整的JavaScipt表达式支持 * **限制:每个绑定都只能包含单个表达式** { { num+1}} { { flag ? 'true':'false'}} { { message.split('').reverse().join('')}} ## 二 条件渲染 ## ### 2.1 v − i f & v − e l s e v-if\\&v-else v−if&v−else ### * v − i f v-if v−if指令用于条件渲染一块内容。 * 渲染条件:当该块内容的指令的表达式的返回值为 t r u e true true * v − e l s e v-else v−else与 v − i f v-if v−if搭配使用 <template> <div class="hello"> <h1 v-if="flag">{ { flag }}</h1> <h1 v-else>{ { flag }}</h1> </div> </template> <script> export default { name: 'HelloWorld', data() { return { flag: true } } } </script> ![在这里插入图片描述][ada093e7b8b84f24b2477e9e6543ef56.png] ### 2.2 v − s h o w v-show v−show ### * 用于条件性展示的选项指令 * 效果同 v − i f v-if v−if <template> <div class="hello"> <h1 v-show="flag">{ { flag }}</h1> </div> </template> <script> export default { name: 'HelloWorld', data() { return { flag: true } } } </script> ![在这里插入图片描述][ccde32e8f5304b71bd272ddcf1876de0.png] ### 2.3 v − i f v-if v−if与 v − s h o w v-show v−show的区别 ### * v − i f v-if v−if是真正的条件渲染,因为它会确保在切换过程中,条件块内的事件监听器和子组件适当地被销毁和重建。 v − i f v-if v−if同时也是情性的:如果在初始漳染时条件为假,则什么也不做,一直到条件第一次变为真时,才会开始滑染条件块。 * v − s h o w v-show v−show元素总是会被染并目只是简单地基于CSS进行切换 * 总结 * v − i f v-if v−if有更高的切换开销 * v − s h o w v-show v−show有更高的初识渲染开销。 * **如果需要非常频繁地切换**,则使用 v − s h o w v-show v−show较好 * **如果运行时条件很少改变**,则使用 v − i f v-if v−if合适 ## 三 列表渲染 ## ### 3.1 v − f o r v-for v−for列表渲染 ### * v − f o r v-for v−for将一个数组映射为一组元素 * v − f o r v-for v−for指令基于一个数组来渲染一个列表 * v − f o r v-for v−for需要使用 i t e m i n i t e m s item in items iteminitems形式的特殊语法, i t e m s items items是源数据数组, i t e m item item是被迭代的数组元素的别名。 <template> <h1>列表渲染</h1> <div class="hello"> <h1>{ { msg }}</h1> <hr/> <ul> <!-- :key="item.id" 就地原则 --> <li v-for="item in items" :key="item.id"><hr/>{ {item.message}}<hr/></li><hr/> </ul> </div> </template> <script> export default { data() { return { items:[ { id: 1001, message: 'A' }, { id: 1002, message: 'B' }, { id: 1003, message: 'C' } ] } } } </script> ![在这里插入图片描述][1eb6e50f7a2c4174affd20051cef6d4a.png] ### 3.2 v − f o r v-for v−for维护状态 ### * 当vue正在更新使用V-for渲染的元素列表时,默认使用“就地更新”的策略。 * 如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确演染。 * 为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一的key属性。 <!-- :key="item.id" 就地原则 --> <li v-for="item in items" :key="item.id">{ {item.message}}</li> * 一般开发中,对象的属性中一般存在唯一标识字段,也可以使用下标作为唯一key属性字段 <li v-for="(item,index) in items" :key="index">{ {item.message}}</li> ## 四 事件处理 ## ### 4.1 监听事件 ### * v − o n v-on v−on指令用来监听DOM事件,并在触发事件时执行一些JavaScript。 <button v-on:click="num++">数字+1</button> <button @click="display">简写形式@click</button> data() { return { num: 1 } } ### 4.2 事件处理方法 ### * v − o n v-on v−on还可以接收一个需要调用的方法名称。 <button @click="change">改变文本内容</button> methods: { change(event) { this.message='hello Vue'; } } ### 4.3 内联处理器中的方法(事件传递参数) ### <button @click="say('AAA')">AAA</button> methods: { say(message) { alert(message); } } ### 4.4 完整代码和效果展示 ### <template> <h1>事件处理</h1> <div class="hello"> <button v-on:click="num++">数字+1</button> <button v-on:click="num--">数字-1</button> <button @click="display">简写形式@click</button> <h1>{ { num }}</h1> <hr/> <button @click="change">改变文本内容</button> <h1 >{ {message}}</h1> <hr/> <button @click="say('AAA')">AAA</button> <button @click="say('BBB')">BBB</button> </div> </template> <script> export default { data() { return { num: 1, message: 'Hello World', } }, methods: { display(event){ alert("@click=\"xxx\""); }, change(event) { this.message='hello Vue'; }, say(message) { alert(message); } } } </script> ![在这里插入图片描述][38c587f00a3d476e9b2c3fd5e30720eb.gif_pic_center] ## 五 表单输入绑定 ## ### 5.1 v − m o d e l v-model v−model简介 ### * v − m o d e k l v-modekl v−modekl指令在表单`<input> <textarea> <select>`元素上创建双向数据绑定。 * 它会根据控件类型自动选取正确的方法来更新元素。 * 它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。 ### 5.2 修饰符 ### * 默认情况下, v − m o d e l v-model v−model在每次 i n p u t input input事件触发后将输入框的值与数据同步 * . l a z y .lazy .lazy:事件在输入值后同步 * . t r i m .trim .trim:自动过滤用户输入的首尾空白字符 <template> <h1>表单输入绑定</h1> <div class="hello"> <hr/> <input v-model="message1" placeholder="请输入"/> <h1>输入的内容为:{ {message1}}</h1> <hr/> <input v-model.lazy="message2" placeholder="请输入"/> <h1>输入的内容为:{ {message2}}</h1> <hr/> <input v-model.trim="message3" placeholder="请输入"/> <h1>输入的内容为:{ {message3}}</h1> </div> </template> <script> export default { name: 'HelloWorld', props: { msg: String }, data() { return { message1: "", message2: "", message3: "" } } } </script> ![在这里插入图片描述][1807c361c679450186a29fd8a3331e1f.gif_pic_center] ## 六 组件基础 ## ### 6.1 单文本组件 ### * ***Vue单文本组件( . v u e .vue .vue文件)是一种特殊的文本格式***。它允许将Vue组件的***模板、逻辑与样式***封装在单个文件中。 <template> <h1>组件基础</h1> <h1>{ {msg}}</h1> </template> <script> export default { /*导出的名称*/ name: "MyCompent", data() { return { msg: "单文件组件" } } } </script> <!--样式只在当前组建中生效 --> <style scoped> h3{ color: chartreuse; } </style> ### 6.2 加载组件 ### 1. 引入组件 /*第一步:导入组件*/ import MyCompent from "@/components/MyCompent"; 1. 挂载组件 export default { name: 'App', /*第二步:挂载组件*/ components: { MyCompent } } 1. 显示组件 <template> <!-- 第三步:显示组件 --> <MyCompent /> </template> ### 6.3 组件的组织 ### * 一个应用会以一个嵌套的组件树的形式来组织 ![在这里插入图片描述][6359c6dce2514de9a4be84e599030055.png] ## 七 P r o p s Props Props组件交互 ## ### 7.1 Props简介 ### * 组建与组建之间存在来交互 * P r o p s Props Props可以在组件上注册一些自定义属性 * Peops传递参数是没有类型限制的 * 数据类型为数组或者对象的时候,默认值是需要返回工厂模式 ### 7.2 演示 ### #### 7.2.1 App.vue #### <template> <img alt="Vue logo" src="./assets/logo.png"> <MyCompent :title="title" :num="nums" :names="names"/> </template> <script> import MyCompent from "@/components/MyCompent"; export default { name: 'App', data() { return { title: "武林大会", nums: "20", names: ["A","B","C"] } }, components: { MyCompent } } </script> ### 7.2.2 MyCompent.vue ### <template> <h1>props组件交互</h1> <h1>{ {num}}{ {title}}</h1> <ul> <li v-for="(item,index) in names" :key="index" v-html="item"></li> </ul> </template> <script> export default { name: "MyCompent", props:{ title: { type:String, default:"" }, num: { type: Number, default: 1 }, /*数组和对象必须使用函数返回 */ names: { type: Array, default:function () { return [] } } } } </script> <style scoped> </style> ![在这里插入图片描述][15e45320b6d6407bb0aed99a18732497.png] ## 八 自定义事件组件交互 ## ### 8.1 简介 ### * 自定义事件可以在组件中反向传递数据,可以将数据从父组件传递到子组件 * 如果需要将数据从子组件传递到负组件,那么就可以利用自定义事件实现`$emit` * `vm.$emit( event, arg )`触发当前实例上的事件 ### 8.2 演示 ### #### 8.2.1 MyCompent.vue #### <template> <h1>自定义事件组件交互</h1> <hr/> <button @click="send">发送数据</button> </template> <script> export default { name: "MyCompent", data() { return { message: "我是来自子组件的数据" } }, methods: { send() { //参数1:字符串:理论上是随便的,但是需要具有意义 //参数2:传递的数据 this.$emit("onEvent",this.message) } } } </script> <style scoped> </style> #### 8.2.2 App.vue #### <template> <img alt="Vue logo" src="./assets/logo.png"> <MyCompent @onEvent="getData"/> </template> <script> import MyCompent from "./components/MyCompent"; export default { name: 'App', components: { MyCompent }, methods: { getData(data) { alert(data); } } } </script> ![在这里插入图片描述][2d75465c704847cc8919b72d0831a71b.gif_pic_center] ## 九 组件生命周期 ## ### 9.1 生命周期钩子函数 ### * 每个组件在被创建时都要经过1系列的初始化过程。例如需要设置数据监听编译模板,将实例挂载到DOM并在数据变化时更新等。 * 同时在这个过程中也会运行一些叫做***生命周期钩子的函数***,用于给用户在不同阶段添加自己的代码。 ![在这里插入图片描述][4c67c909ae7e452d91b955cb7ae5a70d.png] ### 9.2 钩子函数分类 ### <table> <thead> <tr> <th>函数存作用时期</th> <th>函数名称</th> </tr> </thead> <tbody> <tr> <td>创建时</td> <td>beforeCreate、created</td> </tr> <tr> <td>渲染时</td> <td>beforeMount、mounted</td> </tr> <tr> <td>更新时</td> <td>beforeUpdate、Updated</td> </tr> <tr> <td>卸载时</td> <td>beforeUnmount、unmounted</td> </tr> </tbody> </table> ### 9.3 演示 ### <template> <h1>生命周期函数</h1> <hr/> <button @click="addFunction()">点击</button> <hr/> <h1>{ {msg}}</h1> </template> <script> export default { name: "MyCompent", data() { return { msg: 1 } }, methods: { addFunction(event) { this.msg++; } }, created() { console.log("create--组件创建完成") }, beforeCreate() { console.log("beforeCreate--组件创建完成之前") }, beforeMount() { console.log("beforeMount--组件渲染完成之前") }, mounted() { console.log("beforeMount--渲染完成") //网络请求放到这里 }, beforeUpdate() { console.log("beforeUpdate--更新组件之前") }, unmounted() { console.log("Update--组件卸载完成") }, beforeUnmount() { console.log("beforeDestroy--组件下载完成之前") //卸载之前,把消耗性能的处理都干掉 //定时器 }, destroyed() { console.log("destroy--销毁完成") } } </script> <style scoped> </style> ![在这里插入图片描述][a4c2f739a98e4861ad6e80b759ddec5d.gif_pic_center] ## 十 Vue引入第三方Swiper ## ### 10.1 Swiper简介 ### * Swiper开源、免费、强大的触摸滑动插件 * Swiper是纯javascript打造的滑动特效插件,面向手机、平板电脑等移动终端 * Swiper能实现触屏焦点图、触屏Tab切换、触屏轮播图切换等常用效果 ### 10.2 演示 ### #### 10.2.1 安装Swiper #### cnpm install --save swiper #### 10.2.2 引入&使用 #### <template> <h1>Vue引入第三方</h1> <!--第三步:使用--> <div class="hello"> <Swiper :modules="modules" :pagination="{clickable:true}"> <SwiperSlide> <img src="../assets/logo.png"/> </SwiperSlide> <SwiperSlide> <img src="../assets/logo.png"/> </SwiperSlide> <SwiperSlide> <img src="../assets/logo.png"/> </SwiperSlide> </Swiper> </div> </template> <script> //第二步:引入 import { Swiper,SwiperSlide} from 'swiper/vue'; /*引入过滤器*/ import { Pagination} from 'swiper'; import 'swiper/css'; import 'swiper/css/pagination'; export default { name: 'HelloWorld', data() { return { modules: [Pagination] } }, components: { Swiper, SwiperSlide, } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> img { width: 100%; } </style> ![在这里插入图片描述][4ba5bf5f3bd04479906af3385d1d8e4e.gif_pic_center] ## 十一 Axios网络请求 ## * Axios是一个基于promise的网络请求库 ### 11.1 安装 ### * 在终端进入该项目根目录下,输入已下命令: cnpm install --save axios ![在这里插入图片描述][22cfd3326899404dadcae1936d32afe7.png_pic_center] ### 11.2 引入 ### * 组件中引入`import axios from "axios"` * 全局引入 import { createApp } from 'vue' import App from './App.vue' import './registerServiceWorker' //将Axios挂载到全局 import axios from "axios" const app=createApp(App); app.config.globalProperties.$axios=axios app.mount('#app') ### 11.3 网络请求演示get&post ### * post请求参数需要额外处理 1. 安装依赖(同样是在该项目的根目录下输入) cnpm install --save querystring 1. 转化参数格式 import queryString from "querystring"; queryString.stringify() <template> <div class="hello"> <h1>Axios网络请求</h1> <p>{ {chengpin.title}}</p> </div> </template> <script> import queryString from "querystring"; export default { name: 'HelloWorld', data() { return { chengpin: { } } }, mounted() { this.$axios.get("http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php").then( res=>{ console.log(res.data); } ), this.$axios.post("http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php",queryString.stringify({ user_id: "iwen@qq.com", password: "iwen123", verification_code:"crfvm" })).then( res=>{ console.log(res.data); }) } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> </style> ![在这里插入图片描述][ff36d0c12a6c422eac103e2f744f93d2.png] ### 11.4 网络请求封装 ### * 一个项目中的网络请求会很多,此时就会出现难以管理的问题。 * 解决方案:一般采用的方案就是将网络请求封装起来。 ### 11.5 演示 ### #### 11.5.1 request.js #### * 在src目录下创建文件夹utils,并创建文件request.js,用来存储网络请求对象axios cnpm install --save axios cnpm install --save querystring import axios from "axios" import queryString from "querystring" const instance=axios.create({ //网络请求的公共配置 timeout:5000 }) const errorHandle=(status,info)=> { switch (status){ case 400: console.log("语义有误"); break; case 401: console.log("服务器认证失败"); break; case 403: console.log("服务器拒绝访问"); break; case 404: console.log("地址错误"); break; case 500: console.log("服务器遇到意外"); break; case 502: console.log("服务器无响应"); break; default: console.log(info); break; } } //拦截器 //发送数据之前 instance.interceptors.request.use( config=>{ if(config.method==="post"){ config.data=queryString.stringify(config.data) } //config:包含着网络请求的所有信息 return config; }, error=> { return Promise.reject(error); } ) //响应拦截 instance.interceptors.response.use( response=>{ return response.status===200 ? Promise.resolve(response): Promise.reject(response) }, error=> { const { response}=error; //错误的处理 errorHandle(response.status,response.info) } ) export default instance; #### 11.5.2 index.js #### * 在src目录下创建文件夹 api,并创建文件 index和 path分别来存放网络请求方法和请求路径。 import axios from '../utils/request' import path from "./path" const api={ //成品详细地址 getChengPin() { return axios.get(path.baseUrl+path.chengpin) } } export default api; #### 11.5.3 path.js #### const base={ baseUrl: "http://iwenwiki.com", chengpin: "/api/blueberrypai/getChengpinDetails.php" } export default base; ![在这里插入图片描述][ada11d7a0e0f4d1fb3aded7297455adf.png] ### 11.6 网络请求跨域解决方案 ### * js采用的是同源策略(浏览器的一项安全策略) * **同源策略**浏览器只允许JS码请求和当前所在服务器域名,端口,协议相同的数据接口上的数据。 * 当协议域名端口任意一个不相同时,就会产生跨域问题 * 跨域错误提示信息 ![在这里插入图片描述][7dfa8c9a421341d193829c74738e0b39.png_pic_center] * 主流的跨域解决方案有两种 * 后台解决:cors * 前台解决:proxy const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, //添加下列代码 devServer: { proxy: { '/api': { //协议和服务器域名 target: 'http://iwenwiki.com', changeOrigin: true } } } }) <script> import axios from "axios" export default { name: 'HelloWorld', mounted() { //写入剩下的路径 axios.get("/api/FingerUnion/list.php") .then(res=> { console.log(res.data); }) } } </script> > * 记得需要重启服务器 > ![在这里插入图片描述][12aa4e8c20524a3994b5cf09645b1405.png] ## 十二 Vue引入路由配置 ## * 在Vue中,通过`vue-router`路由管理页面之间的关系 * Vue Router是Vue.js的官方路由。与Vue.js核心深度集成,让用Vue.js构建单页面应用变得轻而易举。 ### 12.1 手动引入步骤 ### * 第一步:安装路由`npm install --save vue-router` * 第二步:配置独立的路由文件`index.js` ![在这里插入图片描述][02e1baca903c4c328a783e080152046a.png] //index.js import { createRouter,createWebHashHistory} from "vue-router" import HomeView from "../views/HomeView"; import AboutView from "../views/AboutView"; //配置信息中需要页面的相关配置 数组类型 const routes=[ { path: "/", component: HomeView }, { path: "/about", component: AboutView } ] /** * createWebHashHistory * home:http://localhost:8080/#/ * about:http://localhost:8080/#/about *原理:a标签的锚点连接 * createWebHistory * home:http://localhost:8080/ * about:http://localhost:8080/about *原理:H5 pushState() 需要后台配合做重定向,否则出现404问题 * @type {Router} */ const router=createRouter({ history:createWebHashHistory(), routes }) export default router; * 第三步:引入路由到项目 ![在这里插入图片描述][3cb16cc5abbd4ea791bcec3ea3689ab3.png] //main.js import { createApp } from 'vue' import App from './App.vue' import './registerServiceWorker' //手动导入和添加 import router from "./router"; //安装路由功能 createApp(App).use(router).mount('#app') * 第四步:指定路由显示入口`<router-view/>` ![在这里插入图片描述][0f80d8b0ab2a487884ddf107c556a130.png] //App.vue <template> <!-- 路由显示入口 --> <router-view></router-view> </template> * 第五步:指定路由跳转 ![在这里插入图片描述][ef1b12fd9379478587c2f3588e52f906.png] //App.vue <template> <span><router-link to="/">首页</router-link></span>| <span><router-link to="/about">关于</router-link></span> </template> ### 12.2 创建项目时引入路由 ### ![在这里插入图片描述][e49323a231af47c68d4c960a49ae8af9.png] ### 12.3 完整代码 ### #### 12.3.1 index.js #### import { createRouter,createWebHashHistory} from "vue-router" import HomeView from "../views/HomeView"; import AboutView from "../views/AboutView"; //配置信息中需要页面的相关配置 数组类型 const routes=[ { path: "/", component: HomeView }, { path: "/about", component: AboutView } ] /** * createWebHashHistory * home:http://localhost:8080/#/ * about:http://localhost:8080/#/about *原理:a标签的锚点连接 * createWebHistory * home:http://localhost:8080/ * about:http://localhost:8080/about *原理:H5 pushState() 需要后台配合做重定向,否则出现404问题 * @type {Router} */ const router=createRouter({ history:createWebHashHistory(), routes }) export default router; #### 12.3.2 HomeView.vue #### <template> <h1>首页</h1> <img src="../assets/girl01.jpg"> </template> <script> export default { name: "HomeView" } </script> <style scoped> img { width: 800px; } </style> #### 12.3.3 AboutView.vue #### <template> <h1>分页面</h1> <img src="../assets/girl02.jpg"> </template> <script> export default { name: "AboutView" } </script> <style scoped> img { width: 800px; } </style> #### 12.3.4 main.js #### import { createApp } from 'vue' import App from './App.vue' import './registerServiceWorker' //手动导入和添加 import router from "./router"; //安装路由功能 createApp(App).use(router).mount('#app') ![在这里插入图片描述][9ce42fcc7cc74dfc955e7b73ad3e0f8d.gif_pic_center] ### 12.4 路由传递参数 ### * 第一步:在路由配置中指定参数的`key` { path: "/newsDetails/:area", name: "newsDetails", component: ()=>import('../views/NewsDetails') } * 第二步:在跳转过程中携带参数 <ul> <li><router-link to="/newsDetails/global">global news</router-link></li> <li><router-link to="/newsDetails/local">local news</router-link></li> </ul> * 第三步:在详情页面读取路由参数携带的参数 <div class="home"> <img alt="Vue logo" src="../assets/logo.png"> </div> ### 12.5 完整代码 ### #### 12.5.1 index.js #### import { createRouter, createWebHashHistory } from 'vue-router' import HomeView from '../views/HomeView.vue' const routes = [ { path: '/', name: 'home', component: HomeView }, { path: '/about', name: 'about', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue') }, { path: "/news", name: "news", /*异步加载,有主语提升主页的加载速度*/ component: () => import('../views/NewsView') }, { path: "/newsDetails/:area", name: "newsDetails", component: ()=>import('../views/NewsDetails') } ] const router = createRouter({ history: createWebHashHistory(), routes }) export default router #### 12.5.2 App.vue #### <template> <h1>路由传递参数</h1> <nav> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link>| <router-link to="/news">News</router-link> </nav> <router-view/> </template> #### 12.5.3 NewsView.vue #### <template> <ul> <li><router-link to="/newsDetails/global">global news</router-link></li> <li><router-link to="/newsDetails/local">local news</router-link></li> </ul> </template> <script> export default { name: "NewsView" } </script> <style scoped> a { text-decoration-line: none; } </style> #### 12.5.4 NewsDetails.vue #### <template> <h1>{ {$route.params.area}} news content</h1> </template> <script> export default { name: "NewsDetails" } </script> <style scoped> </style> ![在这里插入图片描述][07cfb2b0600f47b4960a91630681f5d5.gif_pic_center] ### 12.6 嵌套路由 ### * 第一步:创建子路由要加载显示的页面 <template> <h1>关于{ {$route.params.info}}</h1> </template> <script> export default { name: "AboutUs" } </script> <style scoped> </style> <template> <h1>关于{ {$route.params.info}}</h1> </template> <script> export default { name: "AboutInfo" } </script> <style scoped> </style> * 第二步:在路由配置文件中添加子路由配置 import { createRouter, createWebHashHistory } from 'vue-router' import HomeView from '../views/HomeView.vue' const routes = [ { path: '/', name: 'home', component: HomeView }, { path: '/about', name: 'about', /*重定向*/ redirect: '/about/us/了解信息', component: () => import( '../views/AboutView.vue'), children:[ { /*没有/*/ path: 'us/:info', name: 'us/:info', component:()=>import('../views/AboutUs.vue') }, { /*没有/*/ path: 'info/:info', name: 'info/:info', component:()=>import('../views/AboutInfo.vue') } ] } ] const router = createRouter({ history: createWebHashHistory(), routes }) export default router * 第三步:指定子路由显示位置 <router-view></router-view> * 第四步:添加子路由跳转连接 <router-link to="/about/us/公司">公司简介</router-link>| <router-link to="/about/us/成员">成员简介</router-link>| <router-link to="/about/info/材料">材料信息简介</router-link>| <router-link to="/about/info/产品">产品信息简介</router-link> * 第五步:重定向配置 /*重定向*/ redirect: '/about/us/了解信息', ### 12.7 完整代码 ### #### 12.7.1 index.js #### import { createRouter, createWebHashHistory } from 'vue-router' import HomeView from '../views/HomeView.vue' const routes = [ { path: '/', name: 'home', component: HomeView }, { path: '/about', name: 'about', /*重定向*/ redirect: '/about/us/了解信息', component: () => import( '../views/AboutView.vue'), children:[ { /*没有/*/ path: 'us/:info', name: 'us/:info', component:()=>import('../views/AboutUs.vue') }, { /*没有/*/ path: 'info/:info', name: 'info/:info', component:()=>import('../views/AboutInfo.vue') } ] } ] const router = createRouter({ history: createWebHashHistory(), routes }) export default router #### 12.7.2 AboutView.vue #### <template> <div class="about"> <router-link to="/about/us/公司">公司简介</router-link>| <router-link to="/about/us/成员">成员简介</router-link>| <router-link to="/about/info/材料">材料信息简介</router-link>| <router-link to="/about/info/产品">产品信息简介</router-link> <router-view></router-view> </div> </template> #### 12.7.3 AboutUs.vue #### <template> <h1>关于{ {$route.params.info}}</h1> </template> <script> export default { name: "AboutUs" } </script> <style scoped> </style> #### 12.7.4 AboutInfo.vue #### <template> <h1>关于{ {$route.params.info}}</h1> </template> <script> export default { name: "AboutInfo" } </script> <style scoped> </style> ![在这里插入图片描述][a35205738b0440149de487c9b661e718.gif_pic_center] ## 十三 Vue状态管理(Vuex) ## ### 13.1 Vuex简介 ### * Vuex是一个专为Vue.js应用程序开发的***状态管理模式+库***。 * 它采用集中式存储管储管理应用的所有组件的状态,并以相应的规则保证状态。以一种可预测的方式发生改变。 * 简单理解:***状态管理可以理解成为了更方便地管理组件之间的数据交互提供了一个集中式的管理方案,任何组件都可以按照指定的方式进行读取和改变数据。*** ![在这里插入图片描述][e104f70f36004fed962eb373b1bf9f11.png] ### 13.2 手动引入步骤 ### * 第一步:安装Vues npm install --save vuex //或者 cnpm install --save vuex * 第二步:配置Vuex文件 ![在这里插入图片描述][21eee173b6f648d2bf6df8fc91f3a8c6.png] //index.js import { createStore} from "vuex" //Vuex的核心作用就是帮我们管理组件之间的状态 export default createStore({ //所有的数据状态都存放在这里 state: { counter: 0 } }) * 第三步:在主文件中引入Vuex ![在这里插入图片描述][f680eb5be34d404580ee71fadedf07e1.png] import { createApp } from 'vue' import App from './App.vue' import './registerServiceWorker' import store from './storve' createApp(App).use(store).mount('#app') * 第四步:在组件中读取状态【两种】 * 第一种:普通读取 <h1>App.Vue中引入counter:{ { $store.state.counter}}</h1> * 第二种:快捷读取 <template> <div class="hello"> <h1>HelloWorld中引入counter:{ { $store.state.counter}}</h1> <h1>利用计算属性快捷读取counter:{ { $store.state.counter}}</h1> </div> </template> <script> //第二种方式:快捷读取 利用计算属性的方式 import { mapState} from "vuex" export default { name: 'HelloWorld', props: { msg: String }, computed: { ...mapState(["counter"]) } } </script> ### 13.3 创建项目时引入 ### ![在这里插入图片描述][bbefc21399104cab8bd80609766bef47.png] ### 13.4 完整代码 ### ![在这里插入图片描述][0d514b20cc884138bbbd857447933c04.png] #### 13.4.1 HelloWorld.vue #### <template> <div class="hello"> <h1>HelloWorld中引入counter:{ { $store.state.counter}}</h1> <h1>利用计算属性快捷读取counter:{ { $store.state.counter}}</h1> </div> </template> <script> //第二种方式:快捷读取 利用计算属性的方式 import { mapState} from "vuex" export default { name: 'HelloWorld', props: { msg: String }, computed: { ...mapState(["counter"]) } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> </style> #### 13.4.2 index.js #### import { createStore} from "vuex" //Vuex的核心作用就是帮我们管理组件之间的状态 export default createStore({ //所有的数据状态都存放在这里 state: { counter: 0 } }) #### 13.4.3 App.vue #### <template> <img alt="Vue logo" src="./assets/logo.png"> <HelloWorld msg="Vue状态管理(Vuex)"/> <h1>App.Vue中引入counter:{ { $store.state.counter}}</h1> </template> <script> import HelloWorld from './components/HelloWorld.vue' export default { name: 'App', components: { HelloWorld } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style> #### 13.4.4 main.js #### import { createApp } from 'vue' import App from './App.vue' import './registerServiceWorker' import store from './storve' createApp(App).use(store).mount('#app') ![在这里插入图片描述][d8a84c8d7f1241859575b0f2911fb47e.png] ### 13.5 Vue状态管理核心(Vuex) ### #### 13.5.1 核心概念简介 #### * 最常用的核心概念包括: * State:组件状态 import { createStore } from 'vuex' import axios from 'axios' export default createStore({ state: { counter: -1 } }) * Getter:对Vuex中的数据进行过滤 import { createStore } from 'vuex' import axios from 'axios' export default createStore({ state: { counter: -1 }, getters: { getCounter(state) { return state.counter>0 ? state.counter : "counter数据异常" } } }) * Mutation:更改store中的状态的方法。 * Vuex中mutation非常类似事件:每个mutation都有一个字符串的是件类型和一个回调函数这个回调函数就是实际进行状态更改的地方,并且它会接受state作为第一个参数 import { createStore } from 'vuex' import axios from 'axios' export default createStore({ state: { counter: -1 }, getters: { getCounter(state) { return state.counter>0 ? state.counter : "counter数据异常" } }, mutations: { addCounter(state,num) { state.counter+=num } } }) * Action:本质是mutation * Action提交的是mutation,而不是直接改变状态 * Action可以包含任意异步操作 import { createStore } from 'vuex' import axios from 'axios' export default createStore({ state: { counter: -1 }, getters: { getCounter(state) { return state.counter>0 ? state.counter : "counter数据异常" } }, mutations: { addCounter(state,num) { state.counter+=num } }, actions: { //异步操作 asycAddCounter({commit}) { axios.get("http://iwenwiki.com/api/generator/list.php") .then(res=>{ commit("addCounter",res.data[0]) }) } } }) #### 13.5.2 完整代码演示 #### * index.js import { createStore } from 'vuex' import axios from 'axios' export default createStore({ state: { counter: -1 }, getters: { getCounter(state) { return state.counter>0 ? state.counter : "counter数据异常" } }, mutations: { addCounter(state,num) { state.counter+=num } }, actions: { //异步操作 asycAddCounter({ commit}) { axios.get("http://iwenwiki.com/api/generator/list.php") .then(res=>{ commit("addCounter",res.data[0]) }) } }, modules: { } }) * HelloWorld.vue <template> <div class="hello"> <h1>{ {$store.getters.getCounter}}</h1> <h1>{ {getCounter}}</h1> <button @click="addHander">同步增加</button> <button @click="addAsyncHander">异步增加</button> </div> </template> <script> import { mapGetters,mapMutations,mapActions} from 'vuex' export default { name: 'HelloWorld', props: { msg: String }, computed: { ...mapGetters(["getCounter"]) }, methods: { ...mapMutations(["addCounter"]), ...mapActions(["asycAddCounter"]), addHander() { /*固定调用方式*/ //this.$store.commit("addCounter",3) this.addCounter(3) }, addAsyncHander() { //this.$store.dispatch("asycAddCounter") this.asycAddCounter() } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h3 { margin: 40px 0 0; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style> ![在这里插入图片描述][343362cee2544e90aa0bed5e0511161b.gif_pic_center] [bef38ba7bd7a4591ba4d0e730fbfee8d.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/99400e2550104e14a2200ed700de80ca.png [a0719d2757974521b0f43a66657bcaea.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/e8adc242dd254723a4a01b1d4b4a1489.png [2ed4f5a75d1d40009bbc27781714c3f0.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/a484dff3c6f844b58b188548e86f4839.png [ada093e7b8b84f24b2477e9e6543ef56.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/07d10bbd2c734678ab72bebc8a9d53eb.png [ccde32e8f5304b71bd272ddcf1876de0.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/a4b3fa5adfde458ab629a3cd529f7f19.png [1eb6e50f7a2c4174affd20051cef6d4a.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/c0c76115035c4f159e536e0f13d857a6.png [38c587f00a3d476e9b2c3fd5e30720eb.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/42eea1c89e494ada97e33323872a1a77.gif [1807c361c679450186a29fd8a3331e1f.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/fb2c497f313b48cd8d61fd55dc48de9d.gif [6359c6dce2514de9a4be84e599030055.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/1664d8c8dbaf4cf08f49751b4ff1fb07.png [15e45320b6d6407bb0aed99a18732497.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/4ef03f21141c46cbbb9af69b469e70e5.png [2d75465c704847cc8919b72d0831a71b.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/0a2d0e4c420c4870b89efa8fb09748c5.gif [4c67c909ae7e452d91b955cb7ae5a70d.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/b0aaaa2eb7ed411d921de0a13004a479.png [a4c2f739a98e4861ad6e80b759ddec5d.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/fb8a32158bcf43219c08f2eb3fb9d594.gif [4ba5bf5f3bd04479906af3385d1d8e4e.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/3409e433ee004621b5303dfc37c01f58.gif [22cfd3326899404dadcae1936d32afe7.png_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/8e20f06e48eb46aa8366358cd179a401.png [ff36d0c12a6c422eac103e2f744f93d2.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/05f11250f5434ebdb2b9b21581408bb2.png [ada11d7a0e0f4d1fb3aded7297455adf.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/fb181b1b24904296b600cef0e616cf38.png [7dfa8c9a421341d193829c74738e0b39.png_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/1b4f28e67ff7419a90f998a38206331c.png [12aa4e8c20524a3994b5cf09645b1405.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/c6b0d81bc84547b19718a6c3577b6c30.png [02e1baca903c4c328a783e080152046a.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/2dd8a1bf6b5a48ebb265332dc1e24ee7.png [3cb16cc5abbd4ea791bcec3ea3689ab3.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/1c7929a64a6c49b79ce15ef902db6f24.png [0f80d8b0ab2a487884ddf107c556a130.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/45d9207aae08484b83904c5fa1929ae0.png [ef1b12fd9379478587c2f3588e52f906.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/a2affaea7baf4f9892b13aa05ac25fb6.png [e49323a231af47c68d4c960a49ae8af9.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/38b7e946389643b18de2fd564419391d.png [9ce42fcc7cc74dfc955e7b73ad3e0f8d.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/8eb6e1515c71405bb7bb1090eeb290a1.gif [07cfb2b0600f47b4960a91630681f5d5.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/31bc5431414c41e99fdd4cb1abe8a717.gif [a35205738b0440149de487c9b661e718.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/7904ed9f757d4da8bee247346c1b5d4a.gif [e104f70f36004fed962eb373b1bf9f11.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/c5577d7c352c49fd9ddd01a0d4780035.png [21eee173b6f648d2bf6df8fc91f3a8c6.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/91f9405d18bb4445a47f5d1e190397fb.png [f680eb5be34d404580ee71fadedf07e1.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/bdb6d28b0f3b419ca3df9af11d7b1b14.png [bbefc21399104cab8bd80609766bef47.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/967c0c8779e947a589f1e4003631609a.png [0d514b20cc884138bbbd857447933c04.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/871d848856924f988f0e02f32cd0344e.png [d8a84c8d7f1241859575b0f2911fb47e.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/42427dee821148fca686c8fdc74fe5b4.png [343362cee2544e90aa0bed5e0511161b.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/30/501783e16bd84b4aa89c117081185c82.gif
相关 Vue初识系列【2】内容升级版 文章目录 一 模板语法 1.1 文本 1.2 原始THTML 1.3 属性Attribute 1.4 Java 比眉伴天荒/ 2024年03月30日 15:10/ 0 赞/ 63 阅读
相关 Vue初识系列【2】 一 Vue入门 1.1 Vue简介 Vue 是一套用于构建用户界面的渐进式框架,发布于 2014 年 2 月。与其它大型框架不同的是,Vue 被设计为可以自底 ゞ 浴缸里的玫瑰/ 2024年03月30日 14:15/ 0 赞/ 72 阅读
相关 Vue初识系列【1】 文章目录 一 前端体系 1.1 前端三要素 1.2 JavaScript 框架 1.3 JavaScript 构建工具 逃离我推掉我的手/ 2024年03月30日 14:13/ 0 赞/ 74 阅读
相关 Vue|初识Vue ![968f4c3a9001403aaa609f4e85ac2933.gif][] > Vue是一款用于构建用户界面的JavaScript框架。它基于标准HTML、CSS和J 比眉伴天荒/ 2023年09月24日 17:55/ 0 赞/ 84 阅读
相关 初识Vue 上一节搭建了vue的简单项目的开发环境,这一节来说说Vue的基本使用 > 初识Vue: 1. 想让程序运行,必须要创建一个Vue实例,且传入配置对象(el) 2. 我不是女神ヾ/ 2022年09月13日 15:22/ 0 赞/ 225 阅读
相关 初识vue vue 我们先认识一下什么是vue?其实就是用来构建用户界面的渐进式框架,vue指令就是操作DOM命令而准备的。安装或引用[vue][]你也可以查[开发文档][Link 小灰灰/ 2022年03月20日 13:00/ 0 赞/ 249 阅读
相关 初识VUE 一、什么是vue vue是一个渐进式的前端js框架。所谓渐进式框架,其实就是把框架分层。最核心的部分是视图层渲染,然后往外是组件机制,在这个基础上再加入路由机制、状态管理 深藏阁楼爱情的钟/ 2022年02月25日 12:50/ 0 赞/ 320 阅读
相关 Vue初识 渐进式JavaScript框架 通过对框架的了解与运用程度,来决定其在整个项目中的应用范围,最终可以独立以框架的形式完成整个web前端项目 什么是Vue vue可 清疚/ 2021年11月29日 10:42/ 0 赞/ 341 阅读
相关 Vue初识 一. Vue的简单介绍 前端、django的重点简单描述: """ 1、BBS:前后台不分离的web项目 前台页面主要是通过后台逻 朱雀/ 2021年11月23日 00:32/ 0 赞/ 338 阅读
还没有评论,来说两句吧...