摘要:提交是更改状态的唯一方法,并且这个过程是同步的。对于大型应用,我们会希望把相关代码分割到模块中。
vue-cli 脚手架工具的使用
vue-cli 的依赖
vue-cli 的使用流程
node 的安装
node 是通过js 操作系统接口的语言; npm 是node的包管理工具;所以,安装了node 就可以直接使用npm 下载我们需要的包;
node 可以直接去node官网下载对应系统的安装包,安装提示完成;
然后在 命令行中 通过 npm -v 查看npm 版本,如果有出来代表安装成功;
npm 代理 到cnpm
你直接通过添加 npm 参数 alias 一个新命令:
alias cnpm="npm --registry=https://registry.npm.taobao.org --cache=$HOME/.npm/.cache/cnpm --disturl=https://npm.taobao.org/dist --userconfig=$HOME/.cnpmrc"
然后运行
cnpm install xx -g //全局安装xx
使用 vue-cli
vue init webpack demoName //生成 webpack 为模板的vue项目
运行热更新页面
npm run dev
生成项目可以直接通过 http://localhost:8080/?#/ 访问
如果你是拉别人的项目运行的,要先运行下面的命令,安装依赖包
npm install //或者 npm i
生成一个 静态项目文件(直接打开的静态页面)
npm run build
大多数情况 ,生成的页面是不可以直接打开的;提示只能部署到 服务器上才能正常访问;
如果需要直接本地打开;到项目目录下的config文件夹里的index.js文件中,将build对象下的assetsPublicPath中的“/”,改为“./”即可
生成的文件都是经过压缩的,带md5的文件
export default{} , module.exports = {}, exports { }
在node 的模块中,exports 是 module.exports 的引用;但是在vue 中 不能写成
exports = { porps:["text"] } // 提示 text 未定义;
exports default {} 定义的输出;可以通过 import xx 直接使用(标准ES6);写法是:
exports default {a:123} import a;
module.exports = {} 与 exports default 是等价的
但是如果 同一个js 同时出现 module.exports ={} 和 import 就会报错
module.exports = {a:123} //定义和导出 import a; //引入 //上面两个关键词 不能同时出现在同一个js 中
报错原因如下:
webpack可以使用require和export ,但是不能混合使用import 和module.exports ,不然会报错Cannotvue-router 路由插件安装
assign to read only property "exports" of object "#
安装
cnpm install vue-router
引入为全局插件
配置路由表可以通过router-link 组件 链接到 对应组件;它会解析成类似a 标签
forms //注意书写格式一定要正确father
注意到 生成的url 中前面自动加了个 “#”;可以通过添加 mode:"history", 去掉
原理:https://router.vuejs.org/zh-c...
路由配置中,path 可以设置 url 带参;
带参path定义
表示 apple 后面跟的是参数,不是路径;
带参路径
获取参数
所有的路由都是定义在 routes 生成的页面中的;不能在子组件中重新定义;例子如下:
var router = new VueRouter() import browseMode from "./components/browse-mode.vue" import blogList from "./components/blog-list.vue" import blogArticle from "./components/blog-article.vue" import writePanel from "./components/write-panel.vue" router.map({ "/": { component: browseMode, subRoutes: { "/": { component: blogList }, "/details/:artId": { component: blogArticle } } }, "/edit/:mode": { component: writePanel }, "/search/tag/:tag": { component: browseMode, subRoutes: { "/": { component: blogList } } }, "/search/time/:time": { component: browseMode, subRoutes: { "/": { component: blogList } } }, "/search/title/:title": { component: browseMode, subRoutes: { "/": { component: blogList } } }, }) router.start(App, "app")
路由不是最适合做tab切换的;最适合做tab的是 components 内置组件 ;通过is 控制切换;
var vm = new Vue({ el: "#example", data: { currentView: "home" //改变这个值就会切换内容; }, components: { home: { /* ... */ }, posts: { /* ... */ }, archive: { /* ... */ } } })
定义带参路由 的时候 注意格式是 path:"/box1/:text", 不是path:"/box1:text",(可以理解为/: 后面是参数 ,/后面是路径;)
定义好路由后, router-link 是可以放在任何地方的;它就是一个a标签;点击会切换第一个父级的router-view 中的页面;还要注意格式和传参
获取参数的时候,直接去到参数的值是 this.$route.params.text (text是你定义路由时的 :text )
因为$route 是一个全局变量,你还可以直接在html 中使用它的url参数
{{$route.params.text}}
定义一个多参数 路由的 url
使用时的url可能是这样:
http://localhost:8080/#/apple/red/detail/fool //后面的detail 是固定的。
获取的方法是一样的;
var a = $route.params; //结果 a={ color:red, type:fool }子路由的定义
{ path:"/box1", component:box1, children:[ { // 当 /box1/box1a匹配成功, // box1a会被渲染在 box1的中 path:"box1a", //这里不加 “ / ” component:box1a }, { path:"box1b", component:box1b } ] }, // 要注意,以 / 开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。 //在box1 中定义一行 //子组件 box1a 会自动渲染 到页面中; //如果添加两个 router-link 组件 就可以做tab切换(不建议用路由做tab) //router-link 只会切换 第一个父级的 router-view 中的内容,所以不会刷新整个 box1 ; //path 写成 /box1/box1a 是用了根路径(绝对路径)的形式; //如果写成 {path:"box1a"} 则是相对路径;这样写点击 浏览器的url会写成 http://localhost:8080/box1a //因为顶级路由中是没有定义 box1a 组件的;所以页面空白;
box1a box1b
带参子路由
//路由定义 { path:"/box1/:text", component:box1, children:[ { path:"box1a", component:box1a }, { path:"box1b", component:box1b } ] }, //跳转到 box1 的写法
router-link 中的to 属性,如果只是简单的跳转可以直接写成 to=“box1”;
如果加上:绑定属性;后面的属性可以是简短的 表达式,因此上面的例子可以简化为:
//路由定义 { path:"/box1/:text", component:box1, children:[ { path:"box1a", component:box1a }, { path:"box1b", component:box1b } ] }, //跳转到 box1 的写法
具名路由
router-link 还可以通过 name 指定跳转(具名路由);通过例如 tag="li" 指定包裹标签为a以为的tag;
children:[ { path:"box1a", name:"nameBox", component:box1a } ]用具名路由布局(代替iframe的方式)nameBox //结果:会生成li, 点击router-view 会渲染出 box1a ;注意,path是不可缺少的
export default new Router({ mode:"history", routes: [ { path:"/index", components:{ //注意这里是有 “ s ” 的 default:vuexIndex, //对应在某个页面中定义具名路由left:vuexLeft, // 对应 right:vuexRight //对应 } } ] }) //注意访问的路径 是在components 中定义的path ;
{ path:"/layout", name:"layout", component:layout, children: [ { path: "/", components:{ default:main, leftView:leftView, topBar:topBar }, } ] }
路由的重定向
routes: [ { path:"/", redirect:"/box" //路径不存在就跳转到box }, { path: "/a", redirect: "/b" } //访问a的路径,都跳转到b ]vuex 状态管理插件安装
当vue项目中 组件过多并设计到功能某些数据的时候,管理数据变得复杂,VUEX 就是通过自身的一套数据管理流程帮助你管理 项目数据(状态);
安装
cnpm install vuex --save
实例化
//在main.js 中 import Vuex from "vuex" Vue.use(Vuex); let store = new Vuex.Store({ //Store 是vuex 方法 state:{ //存放变量的地方 total:0, appleTotal:0, bananaTotal:0, }, mutations:{ //定义同步变量的方法 aSetValue(state,value){ state.appleTotal = value state.total = state.appleTotal + state.bananaTotal; }, bSetValue(state,value){ state.bananaTotal = value state.total = state.appleTotal + state.bananaTotal; } } }) new Vue({ el: "#app", store, //在实例中 引入 router, components: { App }, template: "" })
获取值
vuex 的变量store 全局以后可以通过以下语句获取
this.$Store.state.total //组件中总价:{{$store.state.total}}
还可以通过设置getter函数 暴露对应的值
getters:{ getTotal(state){ return state.total } }, //组件中改变vuex变量的值总价:{{$store.getters.getTotal}}
通过在组件中调用以下特定语句改变
methods:{ add(){ this.cnt += 1; //bSetValue 是在vuex实例的mutations中定义的方法 //通过 bSetValue方法 去改变实例的值 this.$store.commit("bSetValue",this.cnt*5) }, minus(){ this.cnt-=1; this.$store.commit("bSetValue",this.cnt*5) } }, // 在vuex 中只有 commit 方法可以改变数据;这里是不建议直接在组件中调用 cmmit 的 // 因为cmmit中只能是同步操作;但是交互往往需要同步数据库 // 更加好的方法是在 actions的方法 中触发 commit;actions 方法支持异步操作; // 所有涉及 后端API 的接口都是放在actions 中进行
actions 属性
mutations:{ aSetValue(state,value){ state.appleTotal = value state.total = state.appleTotal + state.bananaTotal; }, bSetValue(state,value){ state.bananaTotal = value state.total = state.appleTotal + state.bananaTotal; } }, actions:{ // 定义doAfn 方法,间接触发 aSetValue; // 在doAfn 方法是可以用ajax 的 doAfn(context,price){ context.commit("aSetValue",price) }, doBfn(context,price){ context.commit("bSetValue",price) } }
组件中的触发方式 通过 dispatch 触发doAfn;
this.$store.dispatch("doAfn",val*10)vuex 的 modules
Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
官方文档代码
const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> moduleA 的状态 store.state.b // -> moduleB 的状态
官方的文档组织建议:
应用层级的状态应该集中到单个 store 对象中。
提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
异步逻辑都应该封装到 action 里面。
对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:
├── index.html ├── main.js ├── api │ └── ... # 抽取出API请求 ├── components │ ├── App.vue │ └── ... └── store ├── index.js # 我们组装模块并导出 store 的地方 ├── actions.js # 根级别的 action ├── mutations.js # 根级别的 mutation └── modules ├── cart.js # 购物车模块 └── products.js # 产品模块
https://vuex.vuejs.org/zh-cn/...
一个 vuex 小例子父组件
我是left
(我是{{text?text:"路由的方式"}}来的)总价:{{$store.getters.getTotal}}
apple 组件
苹果 库存不够
banana 组件
香蕉 库存不够
main.js
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from "vue" import Vuex from "vuex" import App from "./App" import router from "./router" Vue.config.productionTip = false Vue.use(Vuex); let store = new Vuex.Store({ state:{ total:0, appleTotal:0, bananaTotal:0, }, getters:{ getTotal(state){ return state.total } }, mutations:{ aSetValue(state,value){ state.appleTotal = value state.total = state.appleTotal + state.bananaTotal; }, bSetValue(state,value){ state.bananaTotal = value state.total = state.appleTotal + state.bananaTotal; } }, actions:{ doAfn(context,price){ context.commit("aSetValue",price) }, doBfn(context,price){ context.commit("bSetValue",price) } } }) /* eslint-disable no-new */ new Vue({ el: "#app", store, router, components: { App }, template: "" })
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/92520.html
摘要:静态图片怎么引入对重复元素的遍历产品数据统计数据预测流量分析广告发布在重复的部分用如果某个重复的部分比较分散可用循环,循环是从标签本身就开始的既是的载体,也是与同一个标签的灵活使用遍历的时候可以接受几种赋值方式直接绑定的属性 静态logo图片怎么引入 showImg(https://segmentfault.com/img/bV2iRj?w=350&h=163); 对重复元素...
摘要:重构总共耗时个工作日。第一个重构原因就是没有引入静态类型,导致查看一个对象结构需要翻来覆去在多个文件中查找。第三是各个状态模块耦合度高,加大了代码维护难度。但如果耦合度过高,往往是因为模块没有细分到位。这个项目也不列外。 showImg(https://segmentfault.com/img/remote/1460000019660483); 不知不觉已是2019年的7月,恍惚之间已...
摘要:下滚动到页面底部无限加载数据看到一篇觉得挺实用的就看了下顺便简单翻译了一下给需要的人参考从这个项目中可以加深对的生命周期的理解何时开始请求如何结合使用原生来写事件等等我这里主要是对原文的重点提取和补充本文技术要点生命周期简单用法格式化日期图 Vue下滚动到页面底部无限加载数据Demo 看到一篇Implementing an Infinite Scroll with Vue.js, 觉得...
摘要:笔记说明重学前端是程劭非前手机淘宝前端负责人在极客时间开的一个专栏,每天分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以加入的专栏学习原文有的语音,如有侵权请联系我,邮箱。 笔记说明 重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以...
摘要:笔记说明重学前端是程劭非前手机淘宝前端负责人在极客时间开的一个专栏,每天分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以加入的专栏学习原文有的语音,如有侵权请联系我,邮箱。 笔记说明 重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以...
阅读 1459·2021-09-24 10:38
阅读 1450·2021-09-22 15:15
阅读 3037·2021-09-09 09:33
阅读 877·2019-08-30 11:08
阅读 619·2019-08-30 10:52
阅读 1236·2019-08-30 10:52
阅读 2294·2019-08-28 18:01
阅读 500·2019-08-28 17:55