首页
留言
友情链接
标签页
Search
1
那些顶级不落俗套的“美好祝福”
2,042 阅读
2
如何使用JavaScript获取和设置CSS root变量值
1,374 阅读
3
中国历史朝代顺序图
1,338 阅读
4
春和 《江海共余生》
988 阅读
5
唐诗三百首1-5
785 阅读
分享
Web前端
html&css
javascript
Vue
shopify
shoplazza
后端
ThinkPHP
YII2
服务器端
软件安装
问题合集
故事
诗词
生活
学习
学科
语文
数学
英语
物理
化学
生物
政治
历史
地理
自然
其他
抖音
快手
小视频
随笔
易经
书摘
今日话题
登录
/
注册
Search
标签搜索
一年级语文
sunshine
累计撰写
175
篇文章
累计收到
15
条评论
首页
栏目
分享
Web前端
html&css
javascript
Vue
shopify
shoplazza
后端
ThinkPHP
YII2
服务器端
软件安装
问题合集
故事
诗词
生活
学习
学科
语文
数学
英语
物理
化学
生物
政治
历史
地理
自然
其他
抖音
快手
小视频
随笔
易经
书摘
今日话题
页面
留言
友情链接
标签页
搜索到
11
篇与
的结果
2022-10-13
javascript框架-Vue
Vue.js西岭老湿第0章 Vue介绍0.0 开发工程发展历史通过前面的介绍,我们对目前的项目工程化有了大体了了解,那么其中,在第二阶段的工程化演进中,有一个重要的工程设计理念诞生,他就是著名的 MVC 设计模式,简单点,MVC 其实就是为了项目工程化的一种分工模式;MVC 中的最大缺点就是单项输入输出,所有的 M 的变化及 V 层的变化,必须通过 C 层调用才能展示;随着前端技术及前端工程化体系的发展成熟,参考MVC的设计理念,前端出现了 MVVM 的设计思想,简单理解就是在前端实现数据层与展示层的相互调用,降低业务层面的交互逻辑;后面再进行详细介绍;0.1 Vue 介绍Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的 渐进式框架。注意:Vue是一个框架,相对于 jq 库来说,是由本质区别的;https://cn.vuejs.org/Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性。但它支持所有兼容 ECMAScript 5 的浏览器。0.2 Vue 初体验直接下载引入:https://cn.vuejs.org/v2/guide/installation.htmlCDN 引入:<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>CDN 加速: https://www.bootcdn.cn/<body> <div id="div"> {{user_name}} </div> </body> // 两种引入方式,任意选择 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> <script src="./vue.js"></script> <script> var app = new Vue({ el:'#div', // 设置要操作的元素 // 要替换的额数据 data:{ user_name:'我是一个div' } }) </script>第1章 Vue 实例对象每个 Vue 应用都是通过用 Vue 函数创建一个新的 Vue 实例 开始的:var vm = new Vue({ // 选项 })<body> <div id="div"> {{user_name}} </div> </body> <script src="./vue.js"></script> <script> var app = new Vue({ el:'#div', // 设置要操作的元素 // 要替换的额数据 data:{ user_name:'我是一个div' } }) // 打印Vue实例对象 console.log(app); </script>通过打印实例对象发现,其中 el 被Vue 放入了公有属性中,而data 则被放入了 私有属性中,而 data 中的数据,需要被外部使用,于是 Vue 直接将data 中的属性及属性值,直接挂载到 Vue 实例中,也就是说,data中的数据,我们可以直接使用 app.user_name 直接调用;var app = new Vue({ el:'#div', // 设置要操作的元素 // 要替换的额数据 data:{ user_name:'我是一个div', user:222222 } }) console.log(app.user_name);第 2 章 模板语法-插值我们在前面的代码中,使用 {{}} 的形式在 html 中获取实例对象对象中 data 的属性值;这种使用 {{}} 获取值得方式,叫做 插值 或 插值表达式 ;2.1 文本数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:<span>Message: {{ msg }}</span>Mustache 标签将会被替代为对应数据对象上 msg 属性的值。无论何时,绑定的数据对象上 msg 属性发生了改变,插值处的内容都会更新。即便数据内容为一段 html 代码,仍然以文本内容展示<body> <div id="div"> 文本插值 {{html_str}} </div> </body> <script> var app = new Vue({ el:'#div', data:{ html_str:'<h2>Vue<h2>' } }) </script>浏览器渲染结果:<div id="div">文本插值 <h2>Vue<h2></div>打开浏览器的 REPL 环境 输入 app.html_str = '<s>vue</s>'浏览器渲染结果就会立刻发生改变: <div id="div">文本插值 <s>vue</s></div>2.2 使用 JavaScript 表达式迄今为止,在我们的模板中,我们一直都只绑定简单的属性键值。但实际上,对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持,但是不能使用 JS 语句;(表达式是运算,有结果;语句就是代码,可以没有结果)<body> <div id="div" > {{ un > 3 ? '大' : '小'}} {{ fun() }} </div> </body> <script> var app = new Vue({ el:'#div', data:{ un:2, fun:()=> {return 1+2} } }) </script>第3章 模板语法-指令指令 (Directives) 是带有 v- 前缀的特殊 特性 相当于自定义html属性。指令特性的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM;参考 手册 、 API<body> <div id="div" > <p v-if="seen">现在你看到我了</p> </div> </body> <script> var app = new Vue({ el:'#div', data:{ seen:false } }) </script>这里,v-if 指令将根据表达式 seen 的值的真假来插入/移除 <p> 元素。3.1 v-text / v-html 文本https://cn.vuejs.org/v2/api/#v-texthttps://cn.vuejs.org/v2/api/#v-html<body> <div id="div" {{class}}> <p v-text="seen"></p> <p v-html="str_html"></p> </div> </body> <script> var app = new Vue({ el:'#div', data:{ seen:'<h1>Vue</h1>', str_html:'<h1>Vue</h1>', class:'dd', } }) </script>注意:v-textv-text和差值表达式的区别v-text 标签的指令更新整个标签中的内容(替换整个标签包括标签自身)差值表达式,可以更新标签中局部的内容v-html可以渲染内容中的HTML标签尽量避免使用,否则会带来危险(XSS攻击 跨站脚本攻击)HTML 属性不能用 {{}} 语法3.2 v-bind 属性绑定https://cn.vuejs.org/v2/api/#v-bind可以绑定标签上的任何属性。动态绑定图片的路径<img id=“app” v-bind:src="src" /> <script> var vm = new Vue({ el: '#app', data: { src: '1.jpg' } }); </script>绑定a标签上的id<a id="app" v-bind:href="'del.php?id=' + id">删除</a> <script> var vm = new Vue({ el: '#app', data: { id: 11 } }); </script>绑定class对象语法和数组语法对象语法如果isActive为true,则返回的结果为 <div id="app" class="active"></div><div id="app" v-bind:class="{active: isActive}"> hei </div> <script> var vm = new Vue({ el: '#app', data: { isActive: true } }); </script>数组语法渲染的结果: <div id="app" class="active text-danger"></div><div id="app" v-bind:class="[activeClass, dangerClass]"> hei </div> <script> var vm = new Vue({ el: '#app', data: { activeClass: 'active', dangerClass: 'text-danger' } }); </script>绑定style对象语法和数组语法对象语法渲染的结果: <div id="app" style="color: red; font-size: 40px;">hei</div><div id="app" v-bind:style="{color: redColor, fontSize: font + 'px'}"> hei </div> <script> var vm = new Vue({ el: '#app', data: { redColor: 'red', font: 40 } }); </script>数组语法渲染结果:<div id="app" style="color: red; font-size: 18px;">abc</div><div id="app" v-bind:style="[color, fontSize]">abc</div> <script> var vm = new Vue({ el: '#app', data: { color: { color: 'red' }, fontSize: { 'font-size': '18px' } } }); </script>v-bind 简化语法<div id="app"> <img v-bind:src="imageSrc"> <!-- 缩写 --> <img :src="imageSrc"> </div> <script> var vm = new Vue({ el: '#app', data: { imageSrc: '1.jpg', } }); </script>3.3 数据绑定3.3.1 单向数据绑定<div id="div"> <input type="text" :value="input_val"> </div> <script> var app = new Vue({ el: '#div', data: { input_val: 'hello world ' } }) </script>浏览器渲染结果: <div id="div"><input type="text" value="hello world"></div>通过浏览器 REPL 环境可以进行修改 app.input_val = 'Vue'浏览器渲染结果: <div id="div"><input type="text" value="Vue"></div>我们通过 vue 对象修改数据可以直接影响到 DOM 元素,但是,如果直接修改 DOM 元素,却不会影响到 vue 对象的数据;我们把这种现象称为 单向数据绑定 ;3.3.2 双向数据绑定 v-modelhttps://cn.vuejs.org/v2/api/#v-model<div id="div"> <input type="text" v-model="input_val" > </div> <script> var app = new Vue({ el: '#div', data: { input_val: 'hello world ' } }) </script>通过 v-model 指令展示表单数据,此时就完成了 双向数据绑定 ;不管 DOM 元素还是 vue 对象,数据的改变都会影响到另一个;注意:数据绑定是目前所有MVVM前端框架的核心特性;甚至可以说,没有数据绑定就不能算是框架;3.3.3 双向数据绑定的应用范围文本框 & 文本域<div id="div"> <textarea v-model="inp_val"></textarea> <div>{{ inp_val }}</div> </div> <script> var app = new Vue({ el: '#div', data: { inp_val: '' } }) </script>绑定复选框<div id="div"> 吃饭:<input type="checkbox" value="eat" v-model="checklist"><br> 睡觉:<input type="checkbox" value="sleep" v-model="checklist"><br> 打豆豆:<input type="checkbox" value="ddd" v-model="checklist"><br> {{ checklist }} </div> <script> var vm = new Vue({ el: '#div', data: { checklist: '' // checklist: [] } }); </script>绑定单选框<div id="app"> 男<input type="radio" name="sex" value="男" v-model="sex"> 女<input type="radio" name="sex" value="女" v-model="sex"> <br> {{sex}} </div> <script> var vm = new Vue({ el: '#app', data: { sex: '' } }); </script>修饰符.lazy - 取代 input 监听 change 事件.number - 输入字符串转为有效的数字.trim - 输入首尾空格过滤<div id="div"> <input type="text" v-model.lazy="input_val"> {{input_val}} </div> <script> var app = new Vue({ el: '#div', data: { input_val: 'hello world ' } }) </script>3.4 v-on 绑定事件监听https://cn.vuejs.org/v2/api/#v-onhttps://cn.vuejs.org/v2/guide/events.html3.4.1 基本使用<div id="app"> <input type="button" value="按钮" v-on:click="cli"> </div> <script> var vm = new Vue({ el: '#app', data: { cli:function(){ alert('123'); } } }); </script>上面的代码运行是没有问题的,但是,我们不建议这样做,因为 data 是专门提供数据的对象,事件触发需要执行的是一段代码,需要的是一个方法 (事件处理程序) ;修改代码如下:<div id="app"> <!-- 使用事件绑定的简写形式 --> <input type="button" value="按钮" @click="cli"> </div> <script> var vm = new Vue({ el: '#app', data: {}, // 将事件处理程序写入methods对象 methods: { cli: function () { alert('123'); } } }); </script>向事件处理器中传参<div id="app"> <!-- 直接调用传参即可 --> <input type="button" value="按钮" @click="cli(1,3)"> </div> <script> var vm = new Vue({ el: '#app', data: {}, methods: { // 接受参数 cli: function (a,b) { alert(a+b); } } }); </script>而此时,如果在处理器中需要使用事件对象,则无法获取,我们可以用特殊变量 $event 把它传入方法<input type="button" value="按钮" @click="cli(1,3,$event)">methods: { // 接受参数 cli: function (a,b,ev) { alert(a+b); console.log(ev); } }3.4.2 事件修饰符原生 JS 代码,想要阻止浏览器的默认行为(a标签跳转、submit提交),我们要使用事件对象的 preventDefault() 方法<div id="app"> <a href="http://www.qq.com" id="a">腾百万</a> </div> <script> document.getElementById('a').onclick = (ev)=>{ // 组织浏览器的默认行为 ev.preventDefault(); } </script>使用修饰符 阻止浏览器的默认行为<div id="app"> <a href="http://www.qq.com" @click.prevent="cli">腾百万</a> </div> <script> var vm = new Vue({ el: '#app', data: {}, // 将事件处理程序写入methods对象 methods: { cli: function () { alert('123'); } } }); </script>使用修饰符绑定一次性事件<div id="app"> <a href="http://www.qq.com" @click.once="cli($event)">腾百万</a> </div> <script> var vm = new Vue({ el: '#app', data: {}, // 将事件处理程序写入methods对象 methods: { cli: function (ev) { ev.preventDefault(); alert('123'); } } }); </script>3.4.3 按键修饰符绑定键盘抬起事件,但是只有enter 键能触发此事件<div id="app"> <input type="text" @keyup.enter="keyup"> </div> <script> var vm = new Vue({ el: '#app', data: {}, methods: { keyup:()=>{ console.log('111') } } }); </script>3.4.4 系统修饰符按住 shift 后才能触发点击事件<div id="app"> <input type="button" value="按钮" @click.shift="cli"> </div> <script> var vm = new Vue({ el: '#app', data: {}, methods: { cli:()=>{ console.log('111') } } }); </script>3.4.5 鼠标修饰符鼠标中键触发事件<div id="app"> <input type="button" value="按钮" @click.middle="cli"> </div> <script> var vm = new Vue({ el: '#app', data: {}, methods: { cli:()=>{ console.log('111') } } }); </script>3.4.6 为什么在 HTML 中监听事件?你可能注意到这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用 v-on 有几个好处:扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。3.5 v-show 显示隐藏https://cn.vuejs.org/v2/api/#v-show根据表达式之真假值,切换元素的 display CSS 属性。<div id="app"> <p v-show="is_show">Vue</p> </div> <script> var vm = new Vue({ el:'#app', data:{ is_show:false }, methods:{}, }) </script>案例:点击按钮切换隐藏显示<div id="app"> <input type="button" value="按钮" @click="isshow"> <p v-show="is_show">Vue</p> </div> <script> var vm = new Vue({ el:'#app', data:{ is_show:false }, methods:{ isshow:function(){ this.is_show = !this.is_show; } }, }) </script>3.6 v-if / v-else / v-else-if 条件判断https://cn.vuejs.org/v2/api/#v-if<div id="app"> <div v-if="type === 'A'"> A </div> <div v-else-if="type === 'B'"> B </div> <div v-else-if="type === 'C'"> C </div> <div v-else> Not A/B/C </div> </div> <script> var vm = new Vue({ el: '#app', data: { type: 'F' }, }) </script>3.7 v-for 循环https://cn.vuejs.org/v2/api/#v-for<div id="app"> <ul> <li v-for="(val,key) in arr">{{val}}---{{key}}</li> </ul> <ul> <li v-for="(val,key) in obj">{{val}}---{{key}}</li> </ul> </div> <script> var vm = new Vue({ el: '#app', data: { arr: ['a', 'b', 'c'], obj: { id: 1, name: '李四' } }, }) </script>3.8 v-cloakhttps://cn.vuejs.org/v2/api/#v-cloak和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。<div id="app"> <p>{{obj.id}}</p> </div> <script src="./vue.js"></script> <script> setTimeout(() => { var vm = new Vue({ el: '#app', data: { arr: ['a', 'b', 'c'], obj: { id: 1, name: '李四' } }, }) }, 2000); </script>当我们的网络受阻时,或者页面加载完毕而没有初始化得到 vue 实例时,DOM中的 {{}} 则会展示出来;为了防止现象,我们可以使用 CSS 配合 v-cloak 实现获取 VUE 实例前的隐藏;<style> [v-cloak] { display: none; } </style> <div id="app"> <p v-cloak>{{obj.id}}</p> </div> <script src="./vue.js"></script> <script> setTimeout(() => { var vm = new Vue({ el: '#app', data: { obj: { id: 1, name: '李四' } }, }) }, 2000); </script>3.9 v-oncehttps://cn.vuejs.org/v2/api/#v-once只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过<div id="app"> <p v-once>{{msg}}</p> </div> <script> var vm = new Vue({ el: '#app', data: { msg:'kkk' }, }) </script>第4章 TodoList 案例上市产品: ToDoList 、奇妙清单 、滴答清单学习练手项目 : TodoMVC 、 Vue官方示例为什么选择这样的案例:产品功能简洁,需求明确,所需知识点丰富;实现基本功能容易,涵盖所学基础知识;而可扩展性强,完善所有功能比较复杂,所需技术众多;在学习中,可以灵活取舍;4.1 项目初始化在项目目录中执行 npm install 命令,下载所需静态资源 ; 将Vue.js框架代码,复制到 js 目录,在index.html中引入 vue : <script src="./js/vue.js"></script>同时 在 index.html 最下方,项目引入了app.js ; 而我们要写的 vuejs 代码,都放在这个文件中;4.2 数据遍历const list_data = [ {id:1,title:'吃饭',stat:true}, {id:2,title:'睡觉',stat:false}, {id:3,title:'打豆豆',stat:true}, ] new Vue({ el:'#todoapp', data:{ // list_data:list_data, list_data,// es6属性简写 } })<ul class="todo-list"> <li v-for="(val,key) in list_data"> <div class="view"> <input class="toggle" type="checkbox" v-model="val.stat"> <label>{{val.title}}</label> <button class="destroy"></button> </div> <input class="edit" value="Rule the web"> </li> </ul>4.3 展示无数据状态标签及内容都是在 section footer 两个标签中的,当 list_data 中没有数据时,我们只需要隐藏这个两个标签即可:<section v-if="list_data.length" class="main"> …… </section> <footer v-if="list_data.length" class="footer"> …… </footer>两个标签都有 v-if 判断 ,因此我们可以使用一个 div 包裹两个标签,使 div 隐藏即可:<div v-if="list_data.length"> <section class="main"> …… </section> <footer class="footer"> …… </footer> </div>如果有内容,那么 DOM 书中就会多出一个 div 标签,那么我们可以选择使用 template (vue中的模板标识),有内容时,浏览器渲染不会有此节点;<template v-if="list_data.length"> <section class="main"> …… </section> <footer class="footer"> …… </footer> </template>4.3 添加任务绑定 enter 键盘事件:<input @keyup.enter="addTodo" class="new-todo" placeholder="请输入" autofocus>new Vue({ el:'#todoapp', data:{ // list_data:list_data, list_data,// es6属性简写 }, //添加事件处理器 methods:{ // addTodo:function(){} // 简写形式 addTodo(){ console.log(123); } } })修改代码完成任务添加:methods: { // 添加任务 // addTodo:function(){} // 简写形式 addTodo(ev) { // 获取当前触发事件的元素 var inputs = ev.target; // 获取value值,去除空白后判断,如果为空,则不添加任务 if (inputs.value.trim() == '') { return; } // 组装任务数据 var todo_data = { id: this.list_data.length + 1 + 1, title: inputs.value, stat: false }; // 将数据添加进数组 this.list_data.push(todo_data); // 清空文本框内容 inputs.value = ''; } }4.4 任务的全选与反选点击文本框左边的下箭头,实现全选和反选操作为元素绑定点击事件:<input @click="toggleAll" id="toggle-all" class="toggle-all" type="checkbox">添加处理程序:toggleAll(ev){ // 获取点击的元素 var inputs = ev.target; // console.log(inputs.checked); // 循环所有数据为状态重新赋值 // 因为每个元素的选中状态都是使用 v-model 的双向数据绑定, // 因此 数据发生改变,状态即改变,状态改变,数据也会改变 for(let i=0;i<this.list_data.length;i++){ this.list_data[i].stat = inputs.checked; } }4.5 完成任务如果任务完成,状态改为选中, li 的 class 属性为 completed 时文字有中划线;<li v-for="(val,key) in list_data" v-bind:class="{completed:val.stat}">4.6 删除任务绑定点击事件,将当前索引值传入事件处理程序:<button @click="removeTodo(key)" class="destroy"></button>按照索引,删除相应的数据:removeTodo(key){ this.list_data.splice(key,1); },4.7 删除已完成的任务绑定事件<button @click="removeAllDone" class="clear-completed">Clear completed</button>循环遍历所有数据,删除已被标记为完成的任务:removeAllDone(){ for(let i=0;i<list_data.length;i++){ if(list_data[i].stat == true){ this.list_data.splice(i,1); } } }循环的代码看起来很不舒服, Array.prototype.filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。var arr = [1,4,6,2,78,23,7,3,8]; // 原始写法 // var new_arr = arr.filter(function(v){ // // if(v>8){ // // return true; // // } // return v>8; // }) // 箭头函数写法 // var new_arr = arr.filter((v)=>{ // return v>8; // }) // 精简写法 var new_arr = arr.filter((v)=> v>8); console.log(new_arr);修改项目代码:removeAllDone(){ // 原始循环判断用法 // for(let i=0;i<list_data.length;i++){ // if(list_data[i].stat == true){ // this.list_data.splice(i,1); // } // } // 上面是循环删除符合条件的数据 // 下面是保留不符合条件的数据 // 原始标准库对象方法 // this.list_data = this.list_data.filter(function(v){ // if(v.stat == false){ // return true; // } // }) // 箭头函数方法 // this.list_data = this.list_data.filter(function(v){ // return !v.stat; // }) // 精简方法 this.list_data = this.list_data.filter((v)=>!v.stat); },TodoList案例暂时告一段落,我们并没有将产品做完,因为我们需要用到其他知识了;第5章 MVVM设计思想MVC 设计思想:M: model 数据模型层 提供数据V: Views 视图层 渲染数据C: controller 控制层 调用数据渲染视图MVVM 设计思想:M: model 数据模型层 提供数据V: Views 视图层 渲染数据VM:ViewsModel 视图模型层 调用数据渲染视图 由数据来驱动视图(不需要过多考虑dom操作,把重心放在VM)第6章 其他知识点汇总6.1 计算属性与侦听器6.1.1 计算属性<div id="div"> <input type="text" v-model="xing"> <input type="text" v-model="ming"> {{xing + ming}} </div> <script> var app = new Vue({ el: '#div', data: { xing:'', ming:'', } }) </script>模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。因此我们可以使用方法,来进行运算并返回数据:<div id="div"> <input type="text" v-model="xing"> <input type="text" v-model="ming"> {{ fullname() }} <!-- 一百次调用,观察时间结果--> {{ fullname() }} </div> <script> var app = new Vue({ el: '#div', data: { xing:'', ming:'', }, methods:{ fullname(){ return this.xing+this.ming+Date.now(); } } }) </script>注意,每次在模板中使用 {{ fullname() }} fullname方法就会被调用执行一次;所以,对于任何复杂逻辑,你都应当使用计算属性 ,因为计算属性,会自动缓存数据:<div id="div"> <input type="text" v-model="xing"> <input type="text" v-model="ming"> <br> {{fulln}} <!-- 一百次调用 --> {{fulln}} </div> <script> var app = new Vue({ el: '#div', data: { xing:'', ming:'', }, computed:{ fulln(){ return this.xing+this.ming+Date.now(); } } }) </script>我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。只在相关依赖发生改变时它们才会重新求值;多次调用,计算属性会立即返回之前的计算结果,而不必再次执行函数。6.1.2 利用计算属性获取未完成任务个数<span class="todo-count"><strong>{{getNu}}</strong> item left</span>computed: { // 未完成任务个数 getNu() { return (this.list_data.filter((v) => !v.stat)).length; } }6.1.3 使用侦听器<div id="div"> <input type="text" v-model="xing"> <input type="text" v-model="ming"> {{ fullname }} </div> <script> var app = new Vue({ el: '#div', data: { xing: '', ming: '', fullname:'' }, // 设置侦听器 watch: { // 侦听器中的方法名和要真挺的数据属性名必须一致 // xing 发生变化,侦听器就会被执行,且将变化后的值和变化前的值传入 xing:function(newVal,old_val){ this.fullname = newVal+this.ming; }, ming:function(newVal,oldVal){ this.fullname = this.xing+newVal; } } }) </script>通过上面的案例,我们基本掌握了侦听器的使用,但是我们也发现,与计算属性相比,侦听器并没有优势;也不见得好用,直观上反而比计算属性的使用更繁琐;虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。<div id="div"> <input type="text" v-model="xing"> <input type="text" v-model="ming"> {{ fullname }} </div> <script src="./jq.js"></script> <script> var app = new Vue({ el: '#div', data: { xing: '', ming: '', fullname:'' }, // 设置侦听器 watch: { // 侦听器中的方法名和要真挺的数据属性名必须一致 // xing 发生变化,侦听器就会被执行,且将变化后的值和变化前的值传入 xing:function(newVal,old_val){ // this.fullname = newVal+this.ming; var t = this; // 在侦听器中执行异步网络请求 $.get('./xx.php',(d)=>{ t.fullname = d; }) }, } }) </script>6.2 使用ref操作DOM在学习 jq 时,我们首要任务就是学习选择的使用,因为选择可以极其方便帮助我们获取节点查找dom,因为我们要通过dom展示处理数据。而在Vue中,我们的编程理念发生了变化,变为了数据驱动dom;但有时我们因为某些情况不得不脱离数据操作dom,因此vue为我们提供了 ref 属性获取dom节点;<div id="app"> <input type="button" @click='click' value="按钮"> <br> <p ref="pv">123</p> </div> <script> var app = new Vue({ el: '#app', methods: { click: function () { // 使用原生JS获取dom数据 // var p = document.getElementsByTagName('p')[0].innerHTML; // console.log(p); // 使用vue ref 属性获取dom数据 var d = this.$refs.pv.innerHTML; console.log(d); } } }) console.log(app.$refs); </script>但是在项目开发中,尽可能不要这样做,因为从一定程度上,ref 违背的mvvm设计原则;6.3 过滤器的使用6.3.1 私有(局部)过滤器定义过滤器var app = new Vue({ el: '#app', data:{msg:'UP'}, //定义过滤器 filters:{ // 过滤器的名称及方法 myFilters:function(val){ return val.toLowerCase(); } } })过滤器的使用:Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化转义等操作。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器要被添加到操作值得后面,使用 管道符 | 分割;vue会自动将操作值,以实参的形式传入过滤器的方法中;{{msg|myFilters}}过滤敏感词汇<div id="app"> <input type="text" v-model="msg"> <br> {{msg|myFilters|get3}} </div> <script> var app = new Vue({ el: '#app', data:{ msg:'' }, //定义过滤器 filters:{ // 过滤器的名称及方法 myFilters:function(val){ return val.toLowerCase(); }, get3:function(val){ // 遇到数字替换为 0 // var reg = /\d/g; // return val.replace(reg,0); return val.replace('苍井空','***'); } } }) </script>6.3.2 全局过滤器上面的代码中,myFilters 及 get3 两个过滤器,仅在当前 vue 实例中可用;如果在代码 再次 var app2 = new Vue() 得到变量为 app2 的 vue 实例,则两个过滤器在 app2中都不可用;如果需要过滤器在所有实例对象中可用,我们需要声明 全局过滤器 Vue.filter(名称,处理器)<div id="app"> <input type="text" v-model="msg"> <br> {{msg|myFilters}} </div> <!-- 定义两个DOM节点 --> <div id="app2"> <input type="text" v-model="msg"> <br> {{msg|myFilters|get3}} </div> <script> Vue.filter('myFilters', function (val) { return val.toLowerCase(); }) // 定义两个全局过滤器 Vue.filter('get3', function (val) { return val.replace('苍井空','***'); }) // 两个Vue 实例 var app = new Vue({ el: '#app', data: { msg: '' } }) var app2 = new Vue({ el: '#app2', data: { msg: '' } }) </script>6.4 自定义指令前面我们学过 v-on 、v-model、v-show 等指令,在操作 dom 时使用了 ref 属性,其实之前学过的指令也是操作dom 的一种方式,但有时,这些指令并不能满足我们的需求,因此 vue 允许我们自定义指令来操作 dom6.4.1 全局自定义指令<div id="app"> <p v-setcolor>自定义指令的使用</p> </div> <script> // 注册一个全局自定义指令 `v-focus` Vue.directive('setcolor', { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.style.color = 'red'; } }) var app = new Vue({ el: '#app', }) </script>6.4.2 私有(局部)自定义指令<div id="app"> <p v-setcolor>自定义指令的使用</p> </div> <script> var app = new Vue({ el: '#app', // 注册 局部(私有)指令 directives: { // 定义指令名称 setcolor: { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.style.color = 'red'; } } } }) </script>6.4.3 利用自定义指令使TodoList获取焦点<input @keyup.enter="addTodo" v-getfocus class="new-todo" placeholder="请输入" >// 注册 局部(私有)指令 directives: { // 定义指令名称 getfocus: { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.focus() } } },6.4.4 为自定义指令传值之前学习的指令中,有的指令可以传值,有的则没有,而我们自定的指令中是没有值的,如果想为自定义指令赋值,如下即可:<div id="app"> <p v-setcolor='colors'>自定义指令的使用</p> </div> <script> var app = new Vue({ el: '#app', data:{ colors:'yellow' }, // 注册 局部(私有)指令 directives: { // 定义指令名称 setcolor: { // 自定义指令可以接受第二个参数 inserted: function (el,val) { // 第二个参数中包含了指令名称、挂载名称及数据键值 console.log(val); // 聚焦元素 el.style.color = val.value; } } } }) </script>6.5 过度及动画我们可以使用v-if或者v-show控制dom元素的显示和隐藏<div id="app"> <button @click="go">显示/隐藏</button> <p v-show="is">pppppp1111</p> </div> <script> var app = new Vue({ el: '#app', data: { isShow: true, }, methods: { go() { this.isShow = !this.isShow; } } }) </script>而在显示和隐藏的过程中,我们加入一些动画效果:在进入/离开的过渡中,会有 6 个 class 切换。v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。如果你使用了 <transition name="my-transition">,那么 v-enter 会替换为 my-transition-enter。<style> .fade-enter-active, .fade-leave-active { transition: opacity 1s; } .fade-enter, .fade-leave-to { opacity: 0; } .man-enter-active, .man-leave-active { transition: opacity 4s; } .man-enter, .man-leave-to { opacity: 0; } </style> <div id="app"> <button @click="go">显示/隐藏</button> <transition name="fade"> <p v-show="isShow">pppppp1111</p> </transition> <transition name="man"> <p v-show="isShow">pppppp222</p> </transition> </div> <script> var app = new Vue({ el: '#app', data: { isShow: true, }, methods: { go() { this.isShow = !this.isShow; } } }) </script>这就是Vue中动画及过渡的基本使用方式,因为这些动画效果都需要我们自己写CSS样式,相对比较麻烦,在项目中,大多情况下,我们会借助第三方 CSS 动画库来实现,如:Animate.css ;后面项目中具体使用时,我们在进一步学习第三方 CSS 动画库的使用;第7章 json-server与axios一个项目从立项开始,一般都是前后端同时进行编码工作的,而此时前端需要的接口和数据后台都是无法提供的;7.1 json-server 使用使用全局安装 :npm install json-server -gjson-server 会将一个json文件作为数据库来存储数据,对json数据的格式是有要求的,如data.json的内容:{ "tb1": [ { "id": 1, "title": "标题1", "author": "描述信息1" }, { "id": 2, "title": "标题2", "author": "描述信息2" } ], "tb2": [ { "id": 1, "body": "some comment", "postId": 1 } ], "tb3": { "name": "typicode" } }启动服务: json-server --watch data.json启动成功后,提示信息如下:$ json-server --watch data.json \{^_^}/ hi! Loading data.json Done Resources http://localhost:3000/tb1 http://localhost:3000/tb2 http://localhost:3000/tb3 Home http://localhost:3000 Type s + enter at any time to create a snapshot of the database Watching...得到tb1所有的数据 GET: http://localhost:3000/tb1根据id得到数据 GET : http://localhost:3000/tb1/2添加一条数据 POST: http://localhost:3000/tb1删除一条数据 DELETE: http://localhost:3000/tb1/2模糊查找 GET : http://localhost:3000/tb1?title_like=标题根据id修改数据 PUT: http://localhost:3000/tb1/1注意:json-server 严格遵循 HTTP 请求语义进行数据处理7.2 axios我们在构建应用时需要访问一个 API 并展示其数据。做这件事的方法有好几种,而使用基于 Promise 的 HTTP 客户端 axios 则是其中非常流行的一种。<script src="./axios.js"></script> <script> // 获取全部数据 axios.get('http://localhost:3000/list_data') .then((data)=>{ console.log(data); }); // 获取一条数据 axios.get('http://localhost:3000/list_data/2') .then((data)=>{ console.log(data); }) // 添加一条数据 axios.post('http://localhost:3000/list_data',{stat:false,title:'喝水'}) .then((d)=>{ console.log(d); }).catch(error => console.log(error)) // 删除一条数据 axios.delete('http://localhost:3000/list_data/4') .then((d)=>{ console.log(d); }).catch(error => console.log(error)) // 修改一条数据 axios.put('http://localhost:3000/list_data/6',{title:'hhhhhh'}) .then((d)=>{ console.log(d); }).catch(error => console.log(error)) </script>第8章 重构TodoList案例8.1 启动API接口及数据db.json:{ "list_data": [ { "id": 1, "title": "吃饭", "stat": true }, { "id": 2, "title": "睡觉", "stat": false }, { "id": 3, "title": "打豆豆", "stat": true } ] }启动服务: json-server --watch db.json8.2 获取全部任务el: '#todoapp', data: { // list_data:list_data, list_data:[]// es6属性简写 }, // 当vue实例获取到 el:'#todoapp' 自动调用执行 mounted 方法 mounted:function(){ let url = 'http://localhost:3000/list_data'; axios.get(url).then((backdata)=>{ // console.log(backdata.data); this.list_data = backdata.data; }) },8.3 添加任务…… methods: { // 添加任务事件处理器 // addTodo:function(){} // 简写形式 addTodo(ev) { // 获取当前触发事件的元素 var inputs = ev.target; // 获取value值,去除空白后判断,如果为空,则不添加任务 if (inputs.value.trim() == '') { return; } // 组装任务数据 var todo_data = { // 通过服务器添加数据时,不需要id值 // id: this.list_data.length + 1 + 1, title: inputs.value, stat: false }; let url = 'http://localhost:3000/list_data'; // 将数据提交保存到服务器 axios.post(url,todo_data).then((back_data)=>{ let {data,status} = back_data; if(status == 201){ // console.log(this.list_data); // 数据保存成功后,将数据添加到任务列表展示 this.list_data.push(data); } }) // 清空文本框 inputs.value = ''; }, …… 8.4 删除任务<button @click="removeTodo(key,val.id)" class="destroy"></button>// 删除操作 removeTodo(key,id) { let url = 'http://localhost:3000/list_data/'+id; axios.delete(url).then((back_data)=>{ // 结构对象 let {data,status} = back_data; // console.log(back_data); if(status == 200){ this.list_data.splice(key, 1); } }) },8.5 完成任务<li v-for="(val,key) in list_data" @click="todoDone(key,val.id)" v-bind:class="{completed:val.stat}">// 完成任务 事件处理器(新添加,原案例中没有) todoDone(key,id){ let url = 'http://localhost:3000/list_data/'+id; // 组装数据准备修改服务器数据 setdata = {}; // 注意:事件优先于浏览器渲染执行,获取当前状态 var chestat = this.list_data[key].stat; // 状态取反 setdata.stat = !chestat; setdata.title = this.list_data[key].title; // console.log(setdata); axios.put(url,setdata).then((backdata)=>{ var {data,status} = backdata; // 如果服务器修改失败,则重新渲染DOM节点样式,改回原始状态 // 服务器返回状态有误 if(status != 200){ this.list_data[key].stat = chestat; } // 如果异步执行失败失败,则重新渲染DOM节点样式,改回原始状态 }).catch((err)=>{ if(err){ this.list_data[key].stat = chestat; } }) },8.6 案例中的Bug修改:<button @click.stop="removeTodo(key,val.id)" class="destroy"></button>第9章 组件https://cn.vuejs.org/v2/guide/components.htmlhttps://cn.vuejs.org/v2/guide/components-registration.html9.1 认识组件组件系统是 Vue 的一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。通常一个应用会以一棵嵌套的组件树的形式来组织:例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。9.2 基本使用组件是可复用的 Vue 实例,且带有一个名字。把这个组件作为自定义元素来使用。组件的好处是写一次可以进行任意次数的复用。<div id="app"> <!-- 使用组件 --> <!-- 将组件名直接当做标签名在html代码中使用即可 --> <mytemp></mytemp> <!-- 组件可以进行任意次数的复用 --> <mytemp></mytemp> </div> <script> // 定义一个名为 mytemp 的新组件 Vue.component('mytemp',{ // template属性的值,作为组件的内容 // vue 会把这个值替换到html中并会被浏览器渲染 template:"<h2>我是一个组件</h2>" }) var app = new Vue({ el: '#app', }) </script>上面代码中我们直接使用 Vue.component() 方法定义了组件,而这个 mytemp 组件可以用在所有 vue 实例中,这种组件被称为 全局组件在具体的某个vue实例中,也可以定义组件,但是组件仅会在具体的 vue 实例中起作用,这种组件被称为 局部(私有)组件<div id="app"> <!-- 使用组件 --> <!-- 将组件名直接当做标签名在html代码中使用即可 --> <mytemp></mytemp> </div> <div id="app2"> <!-- 不可用 --> <mytemp></mytemp> </div> <script> var app = new Vue({ el: '#app', // app 的私有组件,其他实例对象不可用 components: { mytemp: { template: "<h2>我是一个组件</h2>", } } }) var app2 = new Vue({ el: '#app2', }) </script>9.3 使用注意组件名如果是驼峰法命名,使用组件时要将大写字母改为小写,并且在前面加上 -组件中的tamplate属性必须有一个唯一的根元素,否则会报错<div id="app"> <!-- 使用组件 --> <!-- 将组件名直接当做标签名在html代码中使用即可 --> <my-temp></my-temp> <!-- 单标签方式使用 --> <my-temp/> </div> <div id="app2"> <!-- 不可用 --> <mytemp></mytemp> </div> <script> var app = new Vue({ el: '#app', // app 的私有组件,其他实例对象不可用 components: { // 驼峰法命名 myTemp: { // 必须有唯一的根标签,多标签报错 template: "<div><h2>我是一个组件</h2><h3>df</h3></div>", } } }) var app2 = new Vue({ el: '#app2', }) </script>9.4 组件的使用CSS 代码* { margin: 0; padding: 0; } .top { width: 100%; height: 80px; background-color: #ccc; } .left { margin-top: 20px; width: 800px; height: 600px; background-color: #ccc; float: left; } .right { margin-top: 20px; width: 400px; height: 600px; background-color: #ccc; float: right; }原始HTML代码<div id="app"> <div class="top">我是顶</div> <div class="left">我是左</div> <div class="right">我是右</div> </div>组件化代码<div id="app"> <tops></tops> <lefts></lefts> <rights></rights> </div> <script> var app = new Vue({ el: '#app', components:{ tops:{ template:'<div class="top">我是顶</div>' }, lefts:{ template:'<div class="left">我是左</div>', }, rights:{ template:'<div class="right">我是右</div>' } } }) </script>9.5 组件中的数据及方法组件是带有名字的可复用的 Vue 实例 ,所以它们与 new Vue 实例对象接收相同的参数选项 data、computed、watch、methods , 但 el例外;虽然组件和实例对象可以接收相同的参数选项,但在具体使用中,vue实例对象的 data 与组件中的 data 还是有差异的, 在我们自己写的组件中,data 必须是一个函数 一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回的对象;<div id="app"> <my-temp></my-temp> </div> <script> var app = new Vue({ el: '#app', components: { myTemp: { // 一个组件的 data 选项必须是一个函数 data:function(){ // 将 数据 装入 对象 返回 return {msg:'我是data选项'} }, // 其他选项的使用不受影响 methods:{ cli(){ alert(123); } }, template: "<div @click='cli'>{{msg}}</div>", } } }) </script>除 data 选项外,其他选项的使用都是一样的;9.6 vue实例也是组件通过new Vue() 可以得到一个实例对象,其实这个实例对象就是一个特殊的组件,也有 template 参数,也可以当做组件来使用;<div id="app"> {{msg}} </div> <script> var app = new Vue({ el: '#app', data:{msg:'数据'}, template:'<h2>组件</h2>' }) </script>上面的代码中直接为Vue 实例对象传入了 template 参数,那么 vue 会使用template中的数据替换 el 选中的整个 DOM 节点 , 因此 data 选项中的的数据也不会绑定,因为在绑定数据之前,整个 DOM 节点包括节点中 {{msg}} 都会被替换;如果想让数据正常绑定,我们可以在 template 数据中加入 {{msg}}<div id="app"> {{msg}} </div> <script> var app = new Vue({ el: '#app', data:{msg:'数据'}, template:'<h2>组件{{msg}}</h2>' }) </script>9.7 通过 Prop 向子组件传递数据 *https://cn.vuejs.org/v2/guide/components.html<div id="app"> <mytemp></mytemp> </div> <script> var app = new Vue({ el: '#app', data:{msg:'数据'}, components:{ mytemp:{ template:'<h2>data:{{msg}}</h2>' } } }) </script>运行上面的代码,我们发现,组件 mytemp 并不能获取实例中 data 的数据,这是因为组件与组件之间都拥有各自独立的作用域;vue 在组件中提供了props 选项,props 接受一个在组件中自定义属性的值;<div id="app"> <mytemp cc="我是cc"></mytemp> </div> <script> var app = new Vue({ el: '#app', data:{msg:'数据'}, components:{ mytemp:{ template:'<h2>data:{{cc}}</h2>', props:['cc'], } } }) </script>我们知道了props的用法后,怎么才能将vue实例对象中的数据传入组件中呢?我们可以借助 v-bind 指令来进行传值;<div id="app"> <mytemp v-bind:cc="msg" v-bind:kk="msg2"></mytemp> </div> <script> var app = new Vue({ el: '#app', data:{ msg:'数据', msg2:'数据二' }, components:{ mytemp:{ template:'<h2>data:{{cc}}<br>{{kk}}</h2>', props:['cc','kk'], } } }) </script>vue实例对象也是一个组件,而 mytemp 组件就是运行在 实例对象下面的,这时我们也会将 实例对象称为 父组件,将 mytemp 组件称为 子组件; 而我们上面的代码,实际上已经实现了 父组件向子组件传递数据的 功能;第10章 Vue的生命周期每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。比如 created 钩子可以用来在一个实例被创建之后执行代码:new Vue({ data: { a: 1 }, created: function () { // `this` 指向 vm 实例 console.log('a is: ' + this.a) } }) // => "a is: 1"也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted、updated 和 destroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例。下图展示了实例的生命周期。你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。<div id="app"> {{ msg }} <input type="text" ref="txt" v-model="msg"> </div> <script> var vm = new Vue({ el: "#app", data: { msg: 'hello vue', dataList: [] }, // 在vue对象初始化过程中执行 beforeCreate(){ console.log('beforeCreate'); console.log(this.msg);// undefined }, // 在vue对象初始化完成后执行 created() { console.log('created'); console.log(this.msg);//hello vue } // …… }); </script>第11章 单页应用11.1 单页应用什么是单页应用单页应用(single page web application,SPA),是在一个页面完成所有的业务功能,浏览器一开始会加载必需的HTML、CSS和JavaScript,之后所有的操作都在这张页面完成,这一切都由JavaScript来控制。单页应用优缺点优点操作体验流畅完全的前端组件化缺点首次加载大量资源(可以只加载所需部分)对搜索引擎不友好学习难度相对较高优缺点都很明显,但是我们都还没尝试过就来评价,就会显得空口无凭;接下来我们先来学习制作单页应用,然后再来进行点评;11.2 vue路由插件vue-routerhttps://cn.vuejs.org/v2/guide/routing.htmlhttps://router.vuejs.org/zh/<!-- 引入路由 --> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <div id="app"> <ul> <li><a href="#/login">登录</a></li> <li><a href="#/register">注册</a></li> </ul> <!-- 路由中设置的组件会替换router-view标签 --> <router-view></router-view> </div> <script> // 1:定义路由组件 var login = { template: '<h2>我是登录页面</h2>' } var register = { template: '<h2>注册有好礼</h2>' } // 2:获取路由对象 var router = new VueRouter({ // 定义路由规则 routes: [ // {请求的路径,componet是模板} { path: "/register", component: register }, { path: "/login", component: login }, ] }) var app = new Vue({ el: '#app', // ES6 属性简写 // 3:将router对象传入Vue router }) </script>上例中,在HTML中我们直接使用了 a 标签,但是这样并不好,因为官方为我们提供了 router-link 标签<div id="app"> <ul> <li><router-link to="/login">登录</router-link></li> <li><router-link to="/register">注册</router-link></li> <!-- <li><a href="#/login">登录</a></li> <li><a href="#/register">注册</a></li> --> <!-- router-link 会被解析为a标签 --> <!-- 不同的是,router-link在解析为a标签后, 会自动为点击的 a 标签添加class属性 --> </ul> <!-- 路由中设置的组件会替换router-view标签 --> <router-view></router-view> </div>使用 router-link 的一大好处就是,每当我们点击时,在标签内就会自动帮我们添加 class 属性,而此时,我们就可以利用 class 属性,来定义样式:<style> .router-link-active { color: red; } </style>11.3 动态路由匹配假设有一个用户列表,想要删除某一个用户,需要获取用户的id传入组件内,如何实现呢?此时可以通过路由传参来实现,具体步骤如下:通过 传参,在路径上传入具体的值<router-link to="/users/120">用户管理</router-link>路由规则中增加参数,在path最后增加 :id{ name: 'users', path: '/users/:id', component: Users },在组件内部可以使用,this.$route 获取当前路由对象var Users = { template: '<div>这是用户管理内容 {{ $route.params.id }}</div>', mounted() { console.log(this.$route.params.id); } };第12章 构建一个项目12.0 命令行工具 (CLI)https://cn.vuejs.org/v2/guide/installation.html#%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%B7%A5%E5%85%B7-CLIVue 提供了一个官方的 CLI,为单页面应用 (SPA) 快速搭建繁杂的脚手架。它为现代前端工作流提供了 batteries-included 的构建设置。只需要几分钟的时间就可以运行起来并带有热重载、保存时 lint 校验,以及生产环境可用的构建版本。更多详情可查阅 Vue CLI 的文档。12.1 初始化项目安装 cli 命令工具:npm install -g @vue/cli @vue/cli-init安装成功后,使用 vue -V 命令,查看版本号;使用 vue init webpack myapp 构建一个名为 myapp 的项目:Vue 依然使用询问的方式,让我们对项目有一个初始化的信息Project name:项目名Project description: 项目描述Author: 作者Vue build:第一种:配合大部分的开发人员第二种:仅仅中有runtimeInstall vue-router? 是否安装vue-routerUse ESLint to lint your code?是否使用ESLint来验证我们的语法。Pick an ESLint preser:使用哪种语法规范来检查我们的代码:Standard: 标准规范Airbnb: 爱彼迎规范Set up unit test: 设置单元测试Setup e2e tests: 设置端对端测试Should we run 'npm install':要不要帮忙你下载这个项目需要的第三方包使用npm来下载使用yarn来下载To get started: cd myapps npm run dev // 使用命令启动项目 ----- Your application is running here: http://localhost:8080 打开浏览器,访问 http://localhost:8080 看到浏览器的欢迎界面,表示项目运行成功12.2 项目结构介绍├── build webpack打包相关配置文件目录 ├── config webpack打包相关配置文件目录 ├── node_modules 第三方包 ├── src 项目源码(主战场) │ ├── assets 存储静态资源,例如 css、img、fonts │ ├── components 存储所有公共组件 │ ├── router 路由 │ ├── App.vue 单页面应用程序的根组件 │ └── main.js 程序入口,负责把根组件替换到根节点 ├── static 可以放一些静态资源 │ └── .gitkeep git提交的时候空文件夹不会提交,这个文件可以让空文件夹可以提交 ├── .babelrc 配置文件,es6转es5配置文件,给 babel 编译器用的 ├── .editorconfig 给编辑器看的 ├── .eslintignore 给eslint代码风格校验工具使用的,用来配置忽略代码风格校验的文件或是目录 ├── .eslintrc.js 给eslint代码风格校验工具使用的,用来配置代码风格校验规则 ├── .gitignore 给git使用的,用来配置忽略上传的文件 ├── index.html 单页面应用程序的单页 ├── package.json 项目说明,用来保存依赖项等信息 ├── package-lock.json 锁定第三方包的版本,以及保存包的下载地址 ├── .postcssrc.js 给postcss用的,postcss类似于 less、sass 预处理器 └── README.md 项目说明文档12.3 语法检查注意 :如果我们在 构建项目时 选择了 Use ESLint to lint your code 那么我们在写代码时必须严格遵守 JavaScript Standard Style 代码风格的语法规则:使用两个空格 – 进行缩进字符串使用单引号 – 需要转义的地方除外不再有冗余的变量 – 这是导致 大量 bug 的源头!无分号 – 这没什么不好。不骗你!行首不要以 (, [, or ` 开头这是省略分号时唯一会造成问题的地方 – 工具里已加了自动检测!详情关键字后加空格 if (condition) { ... }函数名后加空格 function name (arg) { ... }坚持使用全等 === 摒弃 == 一但在需要检查 null || undefined 时可以使用 obj == null。一定要处理 Node.js 中错误回调传递进来的 err 参数。使用浏览器全局变量时加上 window 前缀 – document 和 navigator 除外避免无意中使用到了这些命名看上去很普通的全局变量, open, length, event 还有 name。说了那么多,看看这个遵循了 Standard 规范的示例文件 中的代码吧。或者,这里还有一大波使用了此规范的项目 代码可供参考。注意: 如果你不适应这些语法规则,可以在构建项目时不使用 ESLint 的语法检查12.4 项目代码预览12.4.1 知识储备严格模式http://javascript.ruanyifeng.com/advanced/strict.html严格模式主要有以下限制。变量必须声明后再使用函数的参数不能有同名属性,否则报错不能使用with语句不能对只读属性赋值,否则报错不能使用前缀 0 表示八进制数,否则报错不能删除不可删除的属性,否则报错不能删除变量delete prop,会报错,只能删除属性delete global[prop]eval不会在它的外层作用域引入变量eval和arguments不能被重新赋值arguments不会自动反映函数参数的变化不能使用arguments.callee不能使用arguments.caller禁止this指向全局对象不能使用fn.caller和fn.arguments获取函数调用的堆栈增加了保留字(比如protected、static和interface)ES6模块化http://es6.ruanyifeng.com/#docs/module总结:CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用;CommonJS 模块是运行时加载,ES6 模块是编译时输出接口;ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";;ES6 模块之中,顶层的this指向undefined;CommonJS 模块的顶层this指向当前模块;12.4.2 代码加载执行main.js// 入口文件 // 以es6模块的方式引入 vue APP router 三个模块; import Vue from 'vue' import App from './App' import router from './router' Vue.config.productionTip = false; /* eslint-disable no-new */ new Vue({ // 获取节点对象 el: '#app', // 引入路由 router, // 本实例的私有组件 components: { App }, // el 与 template 在同一个实例中出现, // 根据生命周期的执行顺序可知,template中的内容会替换el选中的内容 template: '<App/>' }) roter/index.jsimport Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' // Vue 中插件引入语法 // https://cn.vuejs.org/v2/guide/plugins.html Vue.use(Router) // ES6模块导出语法 export default new Router({ routes: [ // 定义一个路由规则 { path: '/', // 请求路径 name: 'HelloWorld', // 路由名称标识 component: HelloWorld //请求此路由时,使用的组件 } ] }) components/HelloWorld.vueexport default { // 模块名字 name: 'HelloWorld', // 组件中 data 数据必须是一个有返回值的方法 data () { return { msg: 'Welcome to Your Vue.js App' } } }(main.js->template: '<App/>')替换 (index.html->div#app); (index.html-><App/>) --> (components: { App }) ( components: { App }) --> (import App from './App' -> src/App.vue) (App.vue -> <router-view/> -> 路由组件) --> (main.js-> router) ========此项决定了页面展示那个组件内容 ======== ({path: '/',name: 'HelloWorld', component: HelloWorld }) --> (import HelloWorld from '@/components/HelloWorld') (src/components/HelloWorld.vue) --> <router-view/> 12.5 添加自己的路由组件修改 router/index.js ,添加自己的路由import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' // 引入(导入) 组件 import MyRouter from '@/components/MyRouter' Vue.use(Router) // ES6模块导出语法 export default new Router({ routes: [ {path: '/',name: 'HelloWorld', component: HelloWorld }, // 添加自己的路由及组件 { path:'/myrouter', name:'MyRouter', component:MyRouter } ] })在 components 文件夹中添加 MyRouter.vue 文件,写自己的组件代码:<template> <div class="mypage"> {{mydatas}} </div> </template> <script> // 模块化导出 export default { data(){ return {mydatas:'lksadjflks'} } } </script> <style> .mypage{ width: 200px; height: 50px; background: pink } </style> 浏览器渲染效果如下:
2022年10月13日
156 阅读
0 评论
5 点赞
1
2