# Vue_study **Repository Path**: ivanblade/Vue_study ## Basic Information - **Project Name**: Vue_study - **Description**: No description available - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-12-12 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Vue_study ### 相关教程连接 + http://book.nodeing.com/ + http://book.nodeing.com/vue-guide + https://cn.vuejs.org/v2/guide/ ### 环境 + 编辑器推荐vscode,下面的命令可以输入在vscode中的终端里,vscode终端中可以直接使用linux命令行 ### 安装 + 安装node.js + 安装教程 + 安装完成之后验证 ``` node -v 验证node版本检查是否安装成功 ``` + 安装vue ``` npm install -g vue vue -V 验证vue版本验证安装是否成功 ``` + 搭建vue开发环境,安装vue脚手架工具(2.x)(也可以安装3.x或者4.x,貌似命令向下兼容) ``` npm install --global vue-cli 或者 cnmp install --global vue-cli (cnmp安装命令:npm install -g cnpm --registry=https://registry.npm.taobao.org) ``` + 搭建项目 + cd进一个目录作为工作目录 ``` cd xxx ``` + 在工作目录中创建一个项目 ``` vue init webpack vue-demo01(项目名) 如果项目创建失败 nmp install 另一种简单的创建方法(这个启动方式会提醒) vue init webpack-simple vue-demo01 ``` + cd进创建好的项目 ``` cd vue-demo01 ``` + 执行 ``` npm run dev ``` + 3.x脚手架 ``` 日。。。有3.x为什么一开始要装2.x npm uninstall -g vue-cli 卸载当前cli工具 npm install -g @vue/cli 安装3.x脚手架(现在可能直接是更高版本了了) ``` + 启动方式 ``` cd进目录 vue create demo(项目名) 这边会有一系列选项暂不补充看着选。。。 创建完成之后cd进入项目运行查看demo npm run serve 运行 npm run build 编译 ``` ### vue启动jpg(这边前三点用到跨域请求再看,建议直接跳过) + vue-resource(请求数据官方) ``` 安装:npm install vue-resource --save main.js:引入vue-resource import VueResource from 'vue-resource' 使用vue-resource:Vue.use(Vueresource) github搜vue-resource点击进入教程 ``` + axios(请求数据第三方) ``` github搜索axios 哪里用哪里引入:import Axios from 'axios' ``` + fetch josnp(比axios请求数据的种类多一点) + 父子组件传值 ``` 父组件定义标签和传值变量名: 自组价通过props列表接收传值变量名: props:['title','homemsg'] ``` + 父组件主动获取子组件的数据和方法 ``` 1.调用子组件的时候定义一个ref 2.在父组件里通过 this.$refs.son.属性 this.$refs.son.方法 ``` + 子组件主动获取父组件的数据和方法 ``` this.$parent.属性 this.$parent.方法 ``` + vue-router ``` 1.安装 npm install vue-router --save 2.引入并实例化 import VueRouter from 'vue-router' Vue.use(VueRouter) ``` + github搜下面的 + element(pc组件库) + mint(移动端组件库) + 如果github官网中示例无法执行,下载源码包之后点击example/pages导入进项目 + 创建项目时必须选择saas + element食用教程 + 事件修饰符 ``` 百度一下 .prevent可以防止默认行为(如链接跳转) .stop可以防止冒泡 .capture可以防止捕获行为 (捕获行为即由外层标签向内层标签传递的行为,冒泡即内层标签向外层标签传递的行为) .self事件源是自身的时候触发 .once事件只触发一次 ``` + 按键修饰符 ``` 按下回车键会触发func方法 .enter代表回车 .tab .delete .esc .space .up .down ``` + 系统修饰符 ``` .ctrl .alt .meta .shift 表示这个按钮需要按住ctrl点击才有用 ``` + 常用指令 + v-text ```

渲染文本 ``` + v-html ```
message中数据将会被当成html语言解析 ``` + v-show ``` 根据表达式的值确认是否显示

hello vue

flag变量的对错觉得hello是否显示 ``` + v-if ```

优秀

良好

差不多

不及格

``` + v-for ``` new Vue({ el:"#app", data(){ arr:['first','second','third'] } }) ``` + 数组操作 + 非变异方法 执行后数据渲染不会被浏览器同步 + 变异方法 执行后数据渲染会被同步 ``` .push(x):数组后添加一个元素 .pop():删除数组最后一个元素 .shift():删除数组第一个元素 .unshift(x):在数组第一个位置添加元素 .splice(x,y,z,z,z):从序号x开始删除y个元素,从第三个位置开始表示插入元素的值 .sort():排序,需要传入排序函数 降序:this.arr.soft((a,b)=>{return a < b}) .reverse():顺序反转 ``` + 对象属性 + 与数组操作一样采用常规修改浏览器不会同步渲染,一般采用set和delete来修改对象属性 + example ``` vm.$set(this.obj,"num",20) vm.$delete(this.obj,"id") ``` + v-on ``` 绑定事件,简写如:@click ``` + v-bind ``` 百度一下 url:'https://www.baidu.com' url='....' 或者 百度一下 简写百度一下 ``` + v-model ```

{{val}}

双向绑定,更改表单数据,p标签数据也会更改 ``` + v-pre ```

{{data}}

在浏览器中会显示{{data}}而不是data所代表的变量 ``` + v-cloak ``` 结合css防止出现vue初始化之前展示变量名

{{data}}

{{data}}

v-text虽然也有类似效果但是作用范围不大,在隐藏数据较少的情况下可以用v-text,数据量较大的时候用v-cloak ``` + class绑定 ```
cbox为在data中定义的变量,用以动态调整样式
当想要赋予多种样式时可以用数组形式绑定
isActive为布尔型变量,需要在data中定义并用方法初始化 注意这边的大括号中cbox不是变量而是具体的样式名 ``` + style绑定 ```
属性值用引号包含表示变量,style中通过-连接的属性该为分割首字母大写的格式 background-color改为backgroundColor ``` ``` 以上方法不推荐,主要推荐这个方法 data中定义变量 objstyle:{ width:'200px', height:'200px', backgroundColor:'red' } 然后引用
与class一样style也可以用数组形式同时引用多个变量
``` + 表单输入绑定 ``` data定义变量:message:"hello vue" 引用: ``` + 单选框 ``` data定义变量:pick:"" value:选择后提示 name用来传输数据到后台 ``` + 多选框 ``` data定义变量:select_one:"" 这里因为value没有赋值,所以选择之后并不会有相应打印结果 ``` + 复选框 ``` data定义变量:check_one:[] ``` + 修饰符扩 ``` data定义num1:1,num2:2 + = {{num1+num2}} 不用number修饰符的话num1和num2会被当做字符串 去除首尾的空格 ``` + 计算属性 ``` 计算属性定义的方法不需要加(),在方法中定义计算功能需要() 在vue中定义compute类型变量 new Vue({ el:'#app', data:{ msg:"12345" }, computed:{ msg2(){ return msg.split("").reverse().join("") } } }) 计算属性可以被缓存提高性能,变化是依赖变量的变化而变化 而方法函数每次都会被调用 ``` + 组件注册 ```
挂载组件 定义组件 ``` + 父组件向子组件传值 ```
挂载组件 父组件的变量与子组件变量关联,子组件需要传值的变量用props定义 ``` + 子组件向父组件传递数据 ```
这里想要通过点击按钮调用子组件功能,但是功能被写在父组件里,于是只能通过间接调用,现在模板中定义方法变量,再将父组件里的功能赋值给该变量 ``` + template标签 ``` 作用可以理解为批处理操作 示例如上图,div标签以及button标签都会执行循环,不过会影响排列,因为template不是实体节点 ``` + 单文件组件 ``` 1. 引入组件 import nickname from '.......' 2. 包含组件 components:{ 'nickname2':nickname } 3. 挂载组件 在单文件组件中为了防止style之间的冲突,在标签中加入scope用以限定style作用域 ``` + 路由概念 ``` 一开始由后端提出后端根据不同的请求跳转到不同的url 前端路由主要是进行不同组件之间的切换,单页应用是无刷新的,url改变对应的是组件的改变 前端路由的作用就是通过控制不同的url路径切换不同的组件,使两者产生对应关系 ``` + vue-router使用 + 引入包 ``` 在index.js文件中 import Vue from 'vue' import VueRouter from 'vue-router' 以上两个是必要包 import Home from '@/components/Home' import course from '@/components/Course' import vip from '@/components/vip' import answer from '@/components/answer' 这是引入组件 ``` + 使用插件 ``` 在index.js文件中 Vue.use(VueRouter) ``` + 创建实例应用配置 ``` 在index.js文件中 const router = new VueRouter({ routes:[ { path:'/', component:Home }, { path:'/Course', component:course }, { path:'/vip', component:vip }, { path:'answer', component:answer } ] }) ``` + 暴露 ``` 在index.js文件中 export default router ``` + 将url值添加到对应的a标签 ``` 首页 课程 会员 问答 #号必须添加 ``` + 渲染区域 ``` 在入口文件(app.vue)中引入 组件渲染内容会填充在该区域 ``` + hash和history + 模式调用 ``` 在创建路由示例的模块加入下列语句之一就可以切换模式,默认是hash 当模式为history时,a标签url中的‘#’应该删除 const router = new VueRouter({ mode:'history', routes:[ { path:'/', component:Home }, ] }) ``` + hash ``` hash特点是'#'+字符串构造url,无刷新 ``` + history ``` history一般直接通过目录构造不带有# history方式会通过back,forward,go等方式实现页面跳转,会请求后端接口 在h5中history增加了两个方式达到前端路由不刷新的效果pushState和replaceState ``` + router-link + 配置 ``` 在入口文件中a标签可以替换为router-link,以下示例 原本: 首页 课程 会员 问答 替换后 首页 课程 会员 问答 router-link在跳转时会自动加上# ``` + 动态绑定 ``` 首页 data(){ return{ home:'/Home' } } ``` + tag ``` router-link默认渲染成a标签,通过tag可以渲染成其他属性 会员 会员将会被渲染成一个button按钮,点击触发 会员 会员将会被渲染成一个div板块,点击触发 ``` + event ``` 默认点击事件,通过event可以更改为划入划出事件或者其他事件 首页 首页 ``` + 样式 + 局部样式 ``` 首页 ``` + 全局样式 ``` index.js文件下 const router = new VueRouter({ linkActiveClass:'activeclass' }) 入口文件app.vue下 定义style样式 .activeclass{ background-color:white; } ``` + 注意 ``` 全局样式的优先级没有局部样式高,只要写了局部样式class,即使没有写style也不会引用全局样式 ``` + 匹配 + 模糊匹配 ``` 默认匹配方式 ``` + 精确匹配 ``` 首页 加入exact关键字就ok了 ``` + 嵌套路由 ``` 以vip板块的会员等级为例 vip文件下 index.js下引入 import first from '@/components/singles/first' import second from '@/components/singles/second' import third from '@/components/singles/third' index.js下 export default new Router({ routes: [ { path:'/vip', component:vip, children:[ { path:'first', component:first }, { path:'second', component:second }, { path:'third', component:third }] } ] }) ``` + 命名路由 ``` 入口文件下 问答 index.js文件下 export default new Router({ routes: [ { path:'/vip', component:vip, name:'wd' } ] }) ``` + 命名视图 ``` index.js引入文件 import home_left from '@/components/singles/Home_left' import home_right from '@/components/singles/Home_right' index.js下 export default new Router({ routes: [ { path:'/', components:{ default:Home, left:home_left, right:home_right } } } 入口文件下
``` + 重定向 + 概述 ``` 一个发向a的请求被委托被b ``` + 配置 ``` 1.重定向字符串路由 { path:'now', redirect:'/' } 将访问now地址的请求定向回根 2.重定向对象 { path:'now' redirect:{name:'wd'} } 将访问now地址的请求定向到name=wd的路由下 3.给方法 不赘述。。。 ``` + 别名 ``` routes: [ { path:'/', alias:'/now', component:home } } 访问/和now的地址都会转向home组件 ``` + 编程式导航 + 概述 ``` 声明式导航特点是需要在 template 中写跳转链接,通过生成a标签跳转 而编程式导航是通过在 js 中编写代码来实现导航切换。常用方式:back,forward,go,push,replace ``` + push ``` 想要导航到不同的url,则使用router.push方法,这个方法会向history中添加一个新的记录

编程式导航

methods: { push_test(){ this.$router.push('/answer') } 通过点击按钮可以实现跳转,而且浏览器会记录当前url可以回退跳转 ``` + replace ``` 想要导航到不同的url,则使用router.replace方法,这个方法不会向history中添加记录

编程式导航

methods: { push_test(){ this.$router.replace('/vip') } 通过点击按钮可以实现跳转,而且浏览器不会记录当前url,只能回退跳转当前url上一次所在页面 ``` + back ``` 后退到上一个页面(即使通过replace访问的页面也会被跳转) ``` + forward ``` 前进到下一个记录 ``` + go ``` go_test(){ this.$router.go(-1) } go方法可以访问前后记录,并且不需要逐步访问 ``` + 动态路由匹配 + 概述 ``` 当url变化后,我们仍希望用同一个组件渲染 应用场景,当用户的id不同时访问了不同的url但是看见的是同一个渲染界面 ``` + 操作 ``` user组件渲染 index.js路径 { path:'/user/:id?', component:user } :id被认为是动态路径参数 该路径表示如果/user/后面匹配到id也会将它跳转到对应url,?是正则表达,如果匹配不到id也进行跳转 ``` + 监听动态参数 + beforeRouteUpdate ``` 详细参考user.vue beforeRouteUpdate(to,from,next){ // console.log(to)用这个函数查找下一跳信息 this.userInfo=this.user_data.filter((item)=>item.id === to.params.id)[0] // console.log(this.userInfo)通过观察找到id存在的路径,这边id参数在0下面 next() } next()让程序正常跳转 ``` + 路由组件传参 + 概述 ``` 在组件中使用$route会使url和组件高度耦合导致组合只能在特定的url上使用,我们需要通过传参将组件和路由解耦,需要props ``` + 应用 ``` index.js下 { path:'/user/:id?', component:user, props:true } user.vue下 export default{ data(){ return{ user_data:userData, } }, props:['id'], computed: { userInfo(){ return this.user_data.filter((item)=>item.id === this.id)[0] } }, } ``` + 滚动行为 + 概述 ``` scrollBehavior(to,from,savedPosition) to和next即是下一个和上一个 只有在浏览器中的前进后退是记录位置的。。。一般keep-alive保活(还没学到) ``` + 操作 ``` index.js下 mode:'history', scrollBehavior (to, from, savedPosition) { console.log(to) console.log(from) console.log(savedPosition) if (savedPosition) { //如果savedPosition存在,滚动条会自动跳到记录的值的地方 console.log(savedPosition) return savedPosition } else { return { x: 0, y: 0 }//savedPosition也是一个记录x轴和y轴位置的对象 } }, ``` + 过渡效果 + 概述 ``` 通过标签包裹 六类 v-enter,v-enter-to,v-enter-active v-leave,v-leave-to,v-leave-active ``` + 操作 ``` .v-enter{ transform: translateX(-100%); } .v-enter-to{ transform: translateX(0); } .v-enter-active{ transition: 1s; } .v-leave{ transform: translateX(0); } .v-leave-to{ transform: translateX(100%); } .v-leave-active{ transition: 1s; } 标签包裹之后直接写class,名称固定 out-in:先离开后进入 in-out:先进入再离开 name属性 .best-leave-active{ transition: 1s; } 更改name之后v需要替换成name ``` + 全局钩子 + beforeEach ``` { path:'/vip', component:vip, meta:{ require:true } } router.beforeEach((to,from,next) => { console.log('进入路由前'+to.meta) if(to.meta.require) { //need to login in alert('请登录!') }else { next() } }) 这边需要注意钩子应该在vue创建前的位置,所以默认的创建方式可能不会成功 推荐使用 const router = new VueRouter({}) router.beforeEach() export defalut router next()方法用于退出 ``` + afterEach ``` router.beforeEach((to,from) => {}) ``` + 写进路由记录中的钩子 ``` { path:'/Course', component:course, beforeEnter(to,from,next){ alert('course start!') next() } } ``` + 写进组件的钩子 ``` beforeRouteEnter和beforeRouteLeave这边只举一例 ``` ### axios + 概述 ``` 一个基于promise用于浏览器和nodejs的http客户端 作用:发送请求与后端交互 npm install axios --save 在组件中导入 import axios from 'axios' ``` + 组件中使用get方式请求数据 ``` index.js中导入 ``` ``` export default{ data(){ return{ } }, created() { axios({ method:'get', url:'https://easy-mock.com/mock/5c23887d3671d47be5ea8d66/axiosdemo/course/list', }).then((response)=> { console.log(response) }) } } get方式,因为是默认请求方式所以也可以这样: export default{ data(){ return{ } }, created() { axios('https://easy-mock.com/mock/5c23887d3671d47be5ea8d66/axiosdemo/course/list') .then((response) => console.log(response)) } } ``` + mock概述 ``` 虚拟数据接口 easy-mock:https://easy-mock.com mockjs文档:https://github.com/nuysoft/Mock/wiki mockjs案例:http://mockjs.com/examples.html ``` + post请求 ``` export default{ data(){ return{ } }, created() { axios({ method:'get', url:'https://easy-mock.com/mock/5c23887d3671d47be5ea8d66/axiosdemo/course/add', }).then((res)=> { console.log(res) }) } } post和get请求需要的模拟接口类型不同(好吧,废话) ``` + 报错处理 ``` axios('https://easy-mock.com/mock/5c23887d3671d47be5ea8d66/axiosdemo/course/list') .then((response) => console.log(response) ).catch((err)=> { console.log(err) }) ``` + 传参 + get方式传参 ``` axios({ method:'get', url:'https://easy-mock.com/mock/5c23887d3671d47be5ea8d66/axiosdemo/course/list', params:{ title:'xxx', count:30 } }).then((response)=> { console.log(response) }) ``` + post方式传参 ``` axios({ method:'post', url:'https://easy-mock.com/mock/5c23887d3671d47be5ea8d66/axiosdemo/course/add', params:{ title:'xxx', count:30 } }) ``` + 批量请求 ``` created:{ function http1(){ return axios.get('url') } function http2(){ return axios.post('url') } function http3(){ return axios.get('url') } axios.all([http1(),http2(),http3()]).then((res)=>{ console.log(res[0]) console.log(res[1]) console.log(res[2]) }) 服务器会以数组形式返回三个对象,卧槽,三个对象,想想自己一个都没有。。。 ``` + 分割响应结果 ``` axios.all([http1(),http2(),http3()]).then(axios.spread((res1,res2,res3)=> { console.log(res1) console.log(res1) console.log(res1) })) + 创建实例 ``` 在js标签,创建export前创建实例HTTP const HTTP = axios.create({ baseURL:'url_base' }) 在export中 created() { HTTP.get('/xxx/xxx').then((res)=> { console.log(res) }) } 其中get('/xxx/xxx')中是相对路径,会自动与前面的url_base拼接上 实例中参数 baseurl:基础url timeout:默认单位毫秒,超出时间停止请求 其他参数请参照http://book.nodeing.com/ ``` + 拦截器 + 概述 ``` 可以在then和catch之前做一些预处理 ``` + 操作 ``` 基于上面的HTTP实例配置(位置在创建实例后,export之前) HTTP.interceptors.request.use((config)=> { console.log('jpg') return config },(err)=>{ return Promise.reject(err) }) request:发送前 response:响应前 ``` + 全局使用axios ``` 安装插件 npm install vue-axios --save main.js下 引入包 import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios,axios) 部署完成之后在局部组件使用需要加前缀this.就可以了 created() { this.axios({ method:'get', url:'https://easy-mock.com/mock/5c23887d3671d47be5ea8d66/axiosdemo/course/add', }).then((res)=> { console.log(res) }) } ``` + vuex状态管理 + 兄弟组件共享数据 + 经典款 ``` 路线很明朗,子传父再传子 子传父 点击时间出发传输函数,addcar是传递方法名称,用于父组件接守,num是传递参数 父接受 通过Good_num方法处理接受到的数据 methods: { Good_num(num){ this.Goods_num=num } } 父传子 通过绑定到item_num变量完成赋值 子接受即可 props:['item_num'] ``` + 流行款 + 预备步骤 ``` npm install vuex --save 一般要新建一个新的文件夹用来存储vuex的配置文件 该文件暂命名index.js内容如下 import Vue from 'vue' import Vuex from 'vuex' //将vuex作为vue的插件 Vue.use(Vuex) //创建容器 let store = new Vuex.Store() export default store 之后需要在main.js中挂载 import store from '@/store/index.js' new Vue({ el: '#app', router, store, components: { App }, template: '' }) 挂载完成就可以开始应用了 ``` + vuex 启动 + 传递参数包含进vuex实例中,其中state中包含的是传递参数 ``` let store = new Vuex.Store( { state:{ Goods_num:20 } } ) ``` + 传递参数方写入触发方式以及方法 ``` methods: { addcar(){ this.$store.commit('addShopping',this.num) } } 通过this.$store.commit()语句完成传递过程,this.num是预传递参数,addShopping可以认为是是该传递过程的代号 如果想要传递多个参数 this.$store.commit('addShopping',{ n:this.num, m:20 }) 或者可以更换形式 methods: { addcar(){ this.$store.commit( { type:'addShopping', n:this.num, m:20 } ) } } ``` + index.js中通过代号获取传递参数 ``` let store = new Vuex.Store( { state:{ Goods_num:20 }, mutations:{ addShopping(state,temp_info) { // console.log(temp_info) state.Goods_num = temp_info } } } ) 需要该参数的组件只需要引用就好如下

目前选中{{this.$store.state.Goods_num}}件商品

如果是如上多参的情况下修改如下 state.Goods_num = temp_info.n ``` + 核心概念及其他细节 + 参数变换 ``` 在vuex当中唯一能够更改store状态的方法是mutation,其他可能生效的方法多半因为没有开启严格模式 ``` + mutation
mutation中不能写入异步方法 + action ``` 可以用来提交异步代码,但是action不能直接改变store状态,需要将数据传递给mutation间接改变 ``` + 在需要数据的组件中定义接受方式 ``` methods: { addcar(){ this.$store.dispatch('addAction',this.num) } } addcar方式触发数据传输事件,目标为对象为addAction ``` + 在index.js中定义action ``` let store = new Vuex.Store( { state:{ Goods_num:0 }, mutations:{ addShopping(state,payload) { state.Goods_num = payload } }, actions:{ addAction(context,payload){ setTimeout(()=>{ context.commit('addShopping',payload) },1000) } } } ) 使用setTimeout方法作为异步操作,传送数据代号addShopping,action方法addAction接受到数据并传递给mutation方法改变store状态 ``` + getter + 概述 ``` 类似于定义一个全局方法减少不同组件之间的重复代码 ``` + 操作 ``` index.js下通过getters对store中某个变量做方法处理 let store = new Vuex.Store( { state:{ Goods_num:0 }, mutations:{ addShopping(state,payload) { state.Goods_num = payload } }, getters:{ get_num(state){ return state.Goods_num > 25 ? 25 : state.Goods_num } } } ) shoppingcar下渲染即可,其他子组件下也可以直接使用该方式渲染

目前选中{{num}} | {{this.$store.getters.get_num}}件商品

``` + 辅助函数 + 概述 ``` 简化写法 ``` + mapState ``` 这个函数与computed函数形成映射 在需要用到的组件中引入 import {mapState} from 'vuex' ```