A.浏览器端的模块化 1).AMD(Asynchronous Module Definition,异步模块定义) 代表产品为：Require.js 2).CMD(Common Module Definition,通用模块定义) 代表产品为：Sea.js B.服务器端的模块化 服务器端的模块化规范是使用CommonJS规范： 1).使用require引入其他模块或者包 2).使用exports或者module.exports导出模块成员 3).一个文件就是一个模块，都拥有独立的作用域 C.ES6模块化 ES6模块化规范中定义： 1).每一个js文件都是独立的模块 2).导入模块成员使用import关键字 3).暴露模块成员使用export关键字 小结：推荐使用ES6模块化，因为AMD，CMD局限使用与浏览器端，而CommonJS在服务器端使用。ES6模块化是浏览器端和服务器端通用的规范.2.在NodeJS中安装babelA.安装babel打开终端，输入命令：npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node 安装完毕之后，再次输入命令安装：npm install --save @babel/polyfill B.创建babel.config.js在项目目录中创建babel.config.js文件。 编辑js文件中的代码如下： const presets = [ ["@babel/env",{ targets:{ edge:"17", firefox:"60", chrome:"67", safari:"11.1" } }] ] //暴露 module.exports = { presets } C.创建index.js文件在项目目录中创建index.js文件作为入口文件 在index.js中输入需要执行的js代码，例如： console.log("ok"); D.使用npx执行文件打开终端，输入命令：npx babel-node ./index.js 3.设置默认导入/导出A.默认导出export default { 成员A, 成员B, ....... },如下： let num = 100; export default{ num } B.默认导入import 接收名称 from "模块标识符"，如下： import test from "./test.js" 注意：在一个模块中，只允许使用export default向外默认暴露一次成员，千万不要写多个export default。如果在一个模块中没有向外暴露成员，其他模块引入该模块时将会得到一个空对象4.设置按需导入/导出A.按需导出export let num = 998; export let myName = "jack"; export function fn = function(){ console.log("fn") } B.按需导入import { num,fn as printFn ,myName } from "./test.js" //同时导入默认导出的成员以及按需导入的成员 import test,{ num,fn as printFn ,myName } from "./test.js" 注意：一个模块中既可以按需导入也可以默认导入，一个模块中既可以按需导出也可以默认导出5.直接导入并执行代码import "./test2.js"; 6.webpack的概念webpack是一个流行的前端项目构建工具，可以解决目前web开发的困境。webpack提供了模块化支持，代码压缩混淆，解决js兼容问题，性能优化等特性，提高了开发效率和项目的可维护性7.webpack的基本使用A.创建项目目录并初始化创建项目，并打开项目所在目录的终端，输入命令： npm init -y B.创建首页及js文件在项目目录中创建index.html页面，并初始化页面结构：在页面中摆放一个ul，ul里面放置几个li 在项目目录中创建js文件夹，并在文件夹中创建index.js文件 C.安装jQuery打开项目目录终端，输入命令: npm install jQuery -S D.导入jQuery打开index.js文件，编写代码导入jQuery并实现功能： import $ from "jquery"; $(function(){ $("li:odd").css("background","cyan"); $("li:odd").css("background","pink"); }) 注意：此时项目运行会有错误，因为import $ from "jquery";这句代码属于ES6的新语法代码，在浏览器中可能会存在兼容性问题所以我们需要webpack来帮助我们解决这个问题。E.安装webpack1).打开项目目录终端，输入命令: npm install webpack webpack-cli -D 2).然后在项目根目录中，创建一个 webpack.config.js 的配置文件用来配置webpack 在 webpack.config.js 文件中编写代码进行webpack配置，如下： module.exports = { mode:"development"//可以设置为development(开发模式)，production(发布模式) } 补充：mode设置的是项目的编译模式。 如果设置为development则表示项目处于开发阶段，不会进行压缩和混淆，打包速度会快一些 如果设置为production则表示项目处于上线发布阶段，会进行压缩和混淆，打包速度会慢一些 3).修改项目中的package.json文件添加运行脚本dev，如下： "scripts":{ "dev":"webpack" } 注意：scripts节点下的脚本，可以通过 npm run 运行，如： 运行终端命令：npm run dev 将会启动webpack进行项目打包 4).运行dev命令进行项目打包，并在页面中引入项目打包生成的js文件 打开项目目录终端，输入命令: npm run dev 等待webpack打包完毕之后，找到默认的dist路径中生成的main.js文件，将其引入到html页面中。 浏览页面查看效果。 8.设置webpack的打包入口/出口在webpack 4.x中，默认会将src/index.js 作为默认的打包入口js文件 默认会将dist/main.js 作为默认的打包输出js文件 如果不想使用默认的入口/出口js文件，我们可以通过改变 webpack.config.js 来设置入口/出口的js文件，如下： const path = require("path"); module.exports = { mode:"development", //设置入口文件路径 entry: path.join(__dirname,"./src/xx.js"), //设置出口文件 output:{ //设置路径 path:path.join(__dirname,"./dist"), //设置文件名 filename:"res.js" } } 9.设置webpack的自动打包默认情况下，我们更改入口js文件的代码，需要重新运行命令打包webpack，才能生成出口的js文件 那么每次都要重新执行命令打包，这是一个非常繁琐的事情，那么，自动打包可以解决这样繁琐的操作。 实现自动打包功能的步骤如下： A.安装自动打包功能的包:webpack-dev-server npm install webpack-dev-server -D B.修改package.json中的dev指令如下： "scripts":{ "dev":"webpack-dev-server" } C.将引入的js文件路径更改为： D.运行npm run dev，进行打包 E.打开网址查看效果：http://localhost:8080 注意：webpack-dev-server自动打包的输出文件，默认放到了服务器的根目录中. 补充：在自动打包完毕之后，默认打开服务器网页，实现方式就是打开package.json文件，修改dev命令："dev": "webpack-dev-server --open --host 127.0.0.1 --port 9999"10.配置html-webpack-plugin使用html-webpack-plugin 可以生成一个预览页面。 因为当我们访问默认的 http://localhost:8080/的时候，看到的是一些文件和文件夹，想要查看我们的页面 还需要点击文件夹点击文件才能查看，那么我们希望默认就能看到一个页面，而不是看到文件夹或者目录。 实现默认预览页面功能的步骤如下： A.安装默认预览功能的包:html-webpack-plugin npm install html-webpack-plugin -D B.修改webpack.config.js文件，如下： //导入包 const HtmlWebpackPlugin = require("html-webpack-plugin"); //创建对象 const htmlPlugin = new HtmlWebpackPlugin({ //设置生成预览页面的模板文件 template:"./src/index.html", //设置生成的预览页面名称 filename:"index.html" }) C.继续修改webpack.config.js文件，添加plugins信息： module.exports = { ...... plugins:[ htmlPlugin ] } 11.webpack中的加载器通过loader打包非js模块：默认情况下，webpack只能打包js文件，如果想要打包非js文件，需要调用loader加载器才能打包 loader加载器包含： 1).less-loader 2).sass-loader 3).url-loader:打包处理css中与url路径有关的文件 4).babel-loader:处理高级js语法的加载器 5).postcss-loader 6).css-loader,style-loader 注意：指定多个loader时的顺序是固定的，而调用loader的顺序是从后向前进行调用 A.安装style-loader,css-loader来处理样式文件 1).安装包 npm install style-loader css-loader -D 2).配置规则：更改webpack.config.js的module中的rules数组 module.exports = { ...... plugins:[ htmlPlugin ], module : { rules:[ { //test设置需要匹配的文件类型，支持正则 test:/\.css$/, //use表示该文件类型需要调用的loader use:['style-loader','css-loader'] } ] } } B.安装less,less-loader处理less文件 1).安装包 npm install less-loader less -D 2).配置规则：更改webpack.config.js的module中的rules数组 module.exports = { ...... plugins:[ htmlPlugin ], module : { rules:[ { //test设置需要匹配的文件类型，支持正则 test:/\.css$/, //use表示该文件类型需要调用的loader use:['style-loader','css-loader'] }, { test:/\.less$/, use:['style-loader','css-loader','less-loader'] } ] } } C.安装sass-loader,node-sass处理less文件 1).安装包 npm install sass-loader node-sass -D 2).配置规则：更改webpack.config.js的module中的rules数组 module.exports = { ...... plugins:[ htmlPlugin ], module : { rules:[ { //test设置需要匹配的文件类型，支持正则 test:/\.css$/, //use表示该文件类型需要调用的loader use:['style-loader','css-loader'] }, { test:/\.less$/, use:['style-loader','css-loader','less-loader'] }, { test:/\.scss$/, use:['style-loader','css-loader','sass-loader'] } ] } } 补充：安装sass-loader失败时，大部分情况是因为网络原因，详情参考： https://segmentfault.com/a/1190000010984731?utm_source=tag-newest D.安装post-css自动添加css的兼容性前缀（-ie-,-webkit-）1).安装包 npm install postcss-loader autoprefixer -D 2).在项目根目录创建并配置postcss.config.js文件 const autoprefixer = require("autoprefixer"); module.exports = { plugins:[ autoprefixer ] } 3).配置规则：更改webpack.config.js的module中的rules数组 module.exports = { ...... plugins:[ htmlPlugin ], module : { rules:[ { //test设置需要匹配的文件类型，支持正则 test:/\.css$/, //use表示该文件类型需要调用的loader use:['style-loader','css-loader','postcss-loader'] }, { test:/\.less$/, use:['style-loader','css-loader','less-loader'] }, { test:/\.scss$/, use:['style-loader','css-loader','sass-loader'] } ] } } E.打包样式表中的图片以及字体文件在样式表css中有时候会设置背景图片和设置字体文件，一样需要loader进行处理 使用url-loader和file-loader来处理打包图片文件以及字体文件 1).安装包 npm install url-loader file-loader -D 2).配置规则：更改webpack.config.js的module中的rules数组 module.exports = { ...... plugins:[ htmlPlugin ], module : { rules:[ { //test设置需要匹配的文件类型，支持正则 test:/\.css$/, //use表示该文件类型需要调用的loader use:['style-loader','css-loader'] }, { test:/\.less$/, use:['style-loader','css-loader','less-loader'] }, { test:/\.scss$/, use:['style-loader','css-loader','sass-loader'] },{ test:/\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/, //limit用来设置字节数，只有小于limit值的图片，才会转换 //为base64图片 use:"url-loader?limit=16940" } ] } } F.打包js文件中的高级语法：在编写js的时候，有时候我们会使用高版本的js语法有可能这些高版本的语法不被兼容，我们需要将之打包为兼容性的js代码 我们需要安装babel系列的包 A.安装babel转换器 npm install babel-loader @babel/core @babel/runtime -D B.安装babel语法插件包 npm install @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties -D C.在项目根目录创建并配置babel.config.js文件 module.exports = { presets:["@babel/preset-env"], plugins:[ "@babel/plugin-transform-runtime", "@babel/plugin-proposal-class-properties" ] } D.配置规则：更改webpack.config.js的module中的rules数组module.exports = { ...... plugins:[ htmlPlugin ], module : { rules:[ { //test设置需要匹配的文件类型，支持正则 test:/\.css$/, //use表示该文件类型需要调用的loader use:['style-loader','css-loader'] }, { test:/\.less$/, use:['style-loader','css-loader','less-loader'] }, { test:/\.scss$/, use:['style-loader','css-loader','sass-loader'] },{ test:/\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/, //limit用来设置字节数，只有小于limit值的图片，才会转换 //为base64图片 use:"url-loader?limit=16940" },{ test:/\.js$/, use:"babel-loader", //exclude为排除项，意思是不要处理node_modules中的js文件 exclude:/node_modules/ } ] } } 12.Vue单文件组件传统Vue组件的缺陷：全局定义的组件不能重名，字符串模板缺乏语法高亮，不支持css(当html和js组件化时，css没有参与其中)没有构建步骤限制，只能使用H5和ES5，不能使用预处理器（babel）解决方案：使用Vue单文件组件，每个单文件组件的后缀名都是.vue每一个Vue单文件组件都由三部分组成1).template组件组成的模板区域2).script组成的业务逻辑区域3).style样式区域代码如下： 组件代码区域 补充：安装Vetur插件可以使得.vue文件中的代码高亮配置.vue文件的加载器A.安装vue组件的加载器npm install vue-loader vue-template-compiler -D B.配置规则：更改webpack.config.js的module中的rules数组const VueLoaderPlugin = require("vue-loader/lib/plugin"); const vuePlugin = new VueLoaderPlugin(); module.exports = { ...... plugins:[ htmlPlugin, vuePlugin ], module : { rules:[ ...//其他规则 { test:/\.vue$/, loader:"vue-loader", } ] } } 13.在webpack中使用vue上一节我们安装处理了vue单文件组件的加载器，想要让vue单文件组件能够使用，我们必须要安装vue并使用vue来引用vue单文件组件。A.安装Vuenpm install vue -S B.在index.js中引入vue：import Vue from "vue"C.创建Vue实例对象并指定el，最后使用render函数渲染单文件组件const vm = new Vue({el:"#first",render:h=>h(app)})14.使用webpack打包发布项目在项目上线之前，我们需要将整个项目打包并发布。A.配置package.json"scripts":{ "dev":"webpack-dev-server", "build":"webpack -p" } B.在项目打包之前，可以将dist目录删除，生成全新的dist目录15.Vue脚手架Vue脚手架可以快速生成Vue项目基础的架构。A.安装3.x版本的Vue脚手架：npm install -g @vue/cli B.基于3.x版本的脚手架创建Vue项目：1).使用命令创建Vue项目 命令：vue create my-project 选择Manually select features(选择特性以创建项目) 勾选特性可以用空格进行勾选。 是否选用历史模式的路由：n ESLint选择：ESLint + Standard config 何时进行ESLint语法校验：Lint on save babel，postcss等配置文件如何放置：In dedicated config files(单独使用文件进行配置) 是否保存为模板：n 使用哪个工具安装包：npm 2).基于ui界面创建Vue项目 命令：vue ui 在自动打开的创建项目网页中配置项目信息。 3).基于2.x的旧模板，创建Vue项目 npm install -g @vue/cli-init vue init webpack my-project C.分析Vue脚手架生成的项目结构node_modules:依赖包目录 public：静态资源目录 src：源码目录 src/assets:资源目录 src/components：组件目录 src/views:视图组件目录 src/App.vue:根组件 src/main.js:入口js src/router.js:路由js babel.config.js:babel配置文件 .eslintrc.js: 16.Vue脚手架的自定义配置A.通过 package.json 进行配置 [不推荐使用] "vue":{ "devServer":{ "port":"9990", "open":true } } B.通过单独的配置文件进行配置，创建vue.config.js module.exports = { devServer:{ port:8888, open:true } } 17.Element-UI的基本使用Element-UI:一套基于2.0的桌面端组件库官网地址：http://element-cn.eleme.io/#/zh-CNA.安装：npm install element-ui -S B.导入使用：import ElementUI from "element-ui"; import "element-ui/lib/theme-chalk/index.css"; Vue.use(ElementUI)
路由的本质就是一种对应关系，比如说我们在url地址中输入我们要访问的url地址之后，浏览器要去请求这个url地址对应的资源。 那么url地址和真实的资源之间就有一种对应的关系，就是路由 路由分为前端路由和后端路由1).后端路由是由服务器端进行实现，并完成资源的分发2).前端路由是依靠hash值(锚链接)的变化进行实现后端路由性能相对前端路由来说较低，所以，我们接下来主要学习的是前端路由前端路由的基本概念：根据不同的事件来显示不同的页面内容，即事件与事件处理函数之间的对应关系前端路由主要做的事情就是监听事件并分发执行事件处理函数2.前端路由的初体验前端路由是基于hash值的变化进行实现的（比如点击页面中的菜单或者按钮改变URL的hash值，根据hash值的变化来控制组件的切换）核心实现依靠一个事件，即监听hash值变化的事件window.onhashchange = function(){ //location.hash可以获取到最新的hash值 location.hash } 前端路由实现tab栏切换： Document 主页 科技 财经 娱乐 <component :is="comName"></component> 案例效果图：点击每个超链接之后，会进行相应的内容切换，如下：核心思路：在页面中有一个vue实例对象，vue实例对象中有四个组件，分别是tab栏切换需要显示的组件内容在页面中有四个超链接，如下：主页 科技 财经 娱乐 当我们点击这些超链接的时候，就会改变url地址中的hash值，当hash值被改变时，就会触发onhashchange事件在触发onhashchange事件的时候，我们根据hash值来让不同的组件进行显示：window.onhashchange = function() { // 通过 location.hash 获取到最新的 hash 值 console.log(location.hash); switch(location.hash.slice(1)){ case '/zhuye': //通过更改数据comName来指定显示的组件 //因为 <component :is="comName"></component> ，组件已经绑定了comName vm.comName = 'zhuye' break case '/keji': vm.comName = 'keji' break case '/caijing': vm.comName = 'caijing' break case '/yule': vm.comName = 'yule' break } } 3.Vue Router简介它是一个Vue.js官方提供的路由管理器。是一个功能更加强大的前端路由器，推荐使用。Vue Router和Vue.js非常契合，可以一起方便的实现SPA(single page web application,单页应用程序)应用程序的开发。Vue Router依赖于Vue，所以需要先引入Vue，再引入Vue RouterVue Router的特性：支持H5历史模式或者hash模式支持嵌套路由支持路由参数支持编程式路由支持命名路由支持路由导航守卫支持路由过渡动画特效支持路由懒加载支持路由滚动行为4.Vue Router的使用步骤(★★★)A.导入js文件B.添加路由链接:是路由中提供的标签，默认会被渲染为a标签，to属性默认被渲染为href属性，to属性的值会被渲染为#开头的hash地址UserLoginC.添加路由填充位（路由占位符）D.定义路由组件var User = { template:"This is User" }var Login = { template:"This is Login" }E.配置路由规则并创建路由实例var myRouter = new VueRouter({//routes是路由规则数组routes:[//每一个路由规则都是一个对象，对象中至少包含path和component两个属性//path表示 路由匹配的hash地址，component表示路由规则对应要展示的组件对象{path:"/user",component:User},{path:"/login",component:Login}]})F.将路由挂载到Vue实例中new Vue({el:"#app",//通过router属性挂载路由对象router:myRouter})小结：Vue Router的使用步骤还是比较清晰的，按照步骤一步一步就能完成路由操作A.导入js文件B.添加路由链接C.添加路由占位符(最后路由展示的组件就会在占位符的位置显示)D.定义路由组件E.配置路由规则并创建路由实例F.将路由挂载到Vue实例中补充：路由重定向：可以通过路由重定向为页面设置默认展示的组件在路由规则中添加一条路由规则即可，如下：var myRouter = new VueRouter({//routes是路由规则数组routes: [//path设置为/表示页面最初始的地址 / ,redirect表示要被重定向的新地址，设置为一个路由即可{ path:"/",redirect:"/user"},{ path: "/user", component: User },{ path: "/login", component: Login }]})5.嵌套路由，动态路由的实现方式A.嵌套路由的概念(★★★)当我们进行路由的时候显示的组件中还有新的子级路由链接以及内容。嵌套路由最关键的代码在于理解子级路由的概念：比如我们有一个/login的路由那么/login下面还可以添加子级路由，如:/login/account/login/phone参考代码如下：var User = { template: " This is User " } //Login组件中的模板代码里面包含了子级路由链接以及子级路由的占位符 var Login = { template: ` This is Login <router-link to="/login/account">账号密码登录</router-link> <router-link to="/login/phone">扫码登录</router-link> <router-view></router-view> ` } //定义两个子级路由组件 var account = { template:" 账号： 密码： "}; var phone = { template:" 扫我二维码 "}; var myRouter = new VueRouter({ //routes是路由规则数组 routes: [ { path:"/",redirect:"/user"}, { path: "/user", component: User }, { path: "/login", component: Login, //通过children属性为/login添加子路由规则 children:[ { path: "/login/account", component: account }, { path: "/login/phone", component: phone }, ] } ] }) var vm = new Vue({ el: '#app', data: {}, methods: {}, router:myRouter }); 页面效果大致如下：B.动态路由匹配(★★★)var User = { template:"用户：{{$route.params.id}}"}var myRouter = new VueRouter({//routes是路由规则数组routes: [//通过/:参数名 的形式传递参数{ path: "/user/:id", component: User },] })补充：如果使用$route.params.id来获取路径传参的数据不够灵活。1.我们可以通过props来接收参数var User = {props:["id"],template:"用户：{{id}}"}var myRouter = new VueRouter({//routes是路由规则数组routes: [//通过/:参数名 的形式传递参数//如果props设置为true，route.params将会被设置为组件属性{ path: "/user/:id", component: User,props:true },] })2.还有一种情况，我们可以将props设置为对象，那么就直接将对象的数据传递给组件进行使用var User = {props:["username","pwd"],template:"用户：{{username}}---{{pwd}}"}var myRouter = new VueRouter({//routes是路由规则数组routes: [//通过/:参数名 的形式传递参数//如果props设置为对象，则传递的是对象中的数据给组件{ path: "/user/:id", component: User,props:{username:"jack",pwd:123} },] })3.如果想要获取传递的参数值还想要获取传递的对象数据，那么props应该设置为函数形式。var User = {props:["username","pwd","id"],template:"用户：{{id}} -> {{username}}---{{pwd}}"}var myRouter = new VueRouter({//routes是路由规则数组routes: [//通过/:参数名 的形式传递参数//如果props设置为函数，则通过函数的第一个参数获取路由对象//并可以通过路由对象的params属性获取传递的参数//{ path: "/user/:id", component: User,props:(route)=>{return {username:"jack",pwd:123,id:route.params.id}}},] })7.命名路由以及编程式导航A.命名路由：给路由取别名案例：var myRouter = new VueRouter({//routes是路由规则数组routes: [//通过name属性为路由添加一个别名{ path: "/user/:id", component: User, name:"user"},] })//添加了别名之后，可以使用别名进行跳转UserUser//还可以编程式导航myRouter.push( { name:'user' , params: {id:123} } )####B.编程式导航(★★★)页面导航的两种方式：A.声明式导航：通过点击链接的方式实现的导航B.编程式导航：调用js的api方法实现导航Vue-Router中常见的导航方式：this.$router.push("hash地址");this.$router.push("/login");this.$router.push({ name:'user' , params: {id:123} });this.$router.push({ path:"/login" });this.$router.push({ path:"/login",query:{username:"jack"} });this.$router.go( n );//n为数字，参考history.gothis.$router.go( -1 );8.实现后台管理案例(★★★)案例效果：点击左侧的"用户管理","权限管理","商品管理","订单管理","系统设置"都会出现对应的组件并展示内容其中"用户管理"组件展示的效果如上图所示，在用户管理区域中的详情链接也是可以点击的，点击之后将会显示用户详情信息。案例思路：1).先将素材文件夹中的11.基于vue-router的案例.html复制到我们自己的文件夹中。看一下这个文件中的代码编写了一些什么内容，这个页面已经把后台管理页面的基本布局实现了2).在页面中引入vue，vue-router3).创建Vue实例对象，准备开始编写代码实现功能4).希望是通过组件的形式展示页面的主体内容，而不是写死页面结构，所以我们可以定义一个根组件：//只需要把原本页面中的html代码设置为组件中的模板内容即可 const app = { template:` 传智后台管理系统 用户管理 权限管理 商品管理 订单管理 系统设置 添加用户表单 版权信息 ` } 5).当我们访问页面的时候，默认需要展示刚刚创建的app根组件，我们可以创建一个路由对象来完成这个事情,然后将路由挂载到Vue实例对象中即可const myRouter = new VueRouter({ routes:[ {path:"/",component:app} ] }) const vm = new Vue({ el:"#app", data:{}, methods:{}, router:myRouter }) 补充：到此为止，基本的js代码都处理完毕了，我们还需要设置一个路由占位符 <router-view></router-view> 6).此时我们打开页面应该就可以得到一个VueRouter路由出来的根组件了我们需要在这个根组件中继续路由实现其他的功能子组件先让我们更改根组件中的模板：更改左侧li为子级路由链接，并在右侧内容区域添加子级组件占位符const app = { template:` ........ <router-link to="/users">用户管理</router-link> <router-link to="/accesses">权限管理</router-link> <router-link to="/goods">商品管理</router-link> <router-link to="/orders">订单管理</router-link> <router-link to="/systems">系统设置</router-link> <router-view></router-view> ....... ` } 然后，我们要为子级路由创建并设置需要显示的子级组件//建议创建的组件首字母大写，和其他内容区分 const Users = {template:` 用户管理 `} const Access = {template:` 权限管理 `} const Goods = {template:` 商品管理 `} const Orders = {template:` 订单管理 `} const Systems = {template:` 系统管理 `} //添加子组件的路由规则 const myRouter = new VueRouter({ routes:[ {path:"/",component:app , children:[ { path:"/users",component:Users }, { path:"/accesses",component:Access }, { path:"/goods",component:Goods }, { path:"/orders",component:Orders }, { path:"/systems",component:Systems }, ]} ] }) const vm = new Vue({ el:"#app", data:{}, methods:{}, router:myRouter }) 7).展示用户信息列表：A.为Users组件添加私有数据,并在模板中循环展示私有数据​ const Users = { data(){ return { userList:[ {id:1,name:"zs",age:18}, {id:2,name:"ls",age:19}, {id:3,name:"wang",age:20}, {id:4,name:"jack",age:21}, ] } }, template:` 用户管理 编号 姓名 年龄 操作 {{item.id}} {{item.name}} {{item.age}} 详情 `} ​8.当用户列表展示完毕之后，我们可以点击列表中的详情来显示用户详情信息，首先我们需要创建一个组件，用来展示详情信息const UserInfo = { props:["id"], template:` 用户详情 查看 {{id}} 号用户信息 返回用户详情页 `, methods:{ goBack(){ //当用户点击按钮，后退一页 this.$router.go(-1); } } } 然后我们需要设置这个组件的路由规则const myRouter = new VueRouter({ routes:[ {path:"/",component:app , children:[ { path:"/users",component:Users }, //添加一个/userinfo的路由规则 { path:"/userinfo/:id",component:UserInfo,props:true}, { path:"/accesses",component:Access }, { path:"/goods",component:Goods }, { path:"/orders",component:Orders }, { path:"/systems",component:Systems }, ]} ] }) const vm = new Vue({ el:"#app", data:{}, methods:{}, router:myRouter }) 再接着给用户列表中的详情a连接添加事件const Users = { data(){ return { userList:[ {id:1,name:"zs",age:18}, {id:2,name:"ls",age:19}, {id:3,name:"wang",age:20}, {id:4,name:"jack",age:21}, ] } }, template:` 用户管理 编号 姓名 年龄 操作 {{item.id}} {{item.name}} {{item.age}} 详情 `, methods:{ goDetail(id){ this.$router.push("/userinfo/"+id); } } }
原生ajax 基于jQuery的ajax fetch axios 异步 JavaScript的执行环境是「单线程」 所谓单线程，是指JS引擎中负责解释和执行JavaScript代码的线程只有一个，也就是一次只能完成一项任务，这个任务执行完后才能执行下一个，它会「阻塞」其他任务。这个任务可称为主线程 异步模式可以一起执行多个任务 JS中常见的异步调用 定时任何 ajax 事件函数 promise 主要解决异步深层嵌套的问题 promise 提供了简洁的API 使得异步操作更加容易 基于Promise发送Ajax请求 Promise 基本API实例方法.then() 得到异步任务正确的结果 .catch() 获取异常信息 .finally() 成功与否都会执行（不是正式标准） 静态方法.all() Promise.all方法接受一个数组作参数，数组中的对象（p1、p2、p3）均为promise实例（如果不是一个promise，该项会被用Promise.resolve转换为一个promise)。它的状态由这三个promise实例决定 .race() Promise.race方法同样接受一个数组作参数。当p1, p2, p3中有一个实例的状态发生改变（变为fulfilled或rejected），p的状态就跟着改变。并把第一个改变状态的promise的返回值，传给p的回调函数 ​ fetch Fetch API是新的ajax解决方案 Fetch会返回Promise fetch不是ajax的进一步封装，而是原生js，没有使用XMLHttpRequest对象。 fetch(url, options).then(） fetch API 中的 HTTP 请求 fetch(url, options).then(） HTTP协议，它给我们提供了很多的方法，如POST，GET，DELETE，UPDATE，PATCH和PUT 默认的是 GET 请求 需要在 options 对象中 指定对应的 method method:请求使用的方法 post 和 普通 请求的时候 需要在options 中 设置 请求头 headers 和 body fetchAPI 中 响应格式 用fetch来获取数据，如果响应正常返回，我们首先看到的是一个response对象，其中包括返回的一堆原始字节，这些字节需要在收到后，需要我们通过调用方法将其转换为相应格式的数据，比如JSON，BLOB或者TEXT等等 /* Fetch响应结果的数据格式 */ fetch('http://localhost:3000/json').then(function(data){ // return data.json(); // 将获取到的数据使用 json 转换对象 return data.text(); // // 将获取到的数据 转换成字符串 }).then(function(data){ // console.log(data.uname) // console.log(typeof data) var obj = JSON.parse(data); console.log(obj.uname,obj.age,obj.gender) }) axios 基于promise用于浏览器和node.js的http客户端 支持浏览器和node.js 支持promise 能拦截请求和响应 自动转换JSON数据 能转换请求和响应数据 axios基础用法 get和 delete请求传递参数 通过传统的url 以 ? 的形式传递参数 restful 形式传递参数 通过params 形式传递参数 post 和 put 请求传递参数 通过选项传递参数 通过 URLSearchParams 传递参数 # 1. 发送get 请求 axios.get('http://localhost:3000/adata').then(function(ret){ # 拿到 ret 是一个对象 所有的对象都存在 ret 的data 属性里面 // 注意data属性是固定的用法，用于获取后台的实际数据 // console.log(ret.data) console.log(ret) }) # 2. get 请求传递参数 # 2.1 通过传统的url 以 ? 的形式传递参数 axios.get('http://localhost:3000/axios?id=123').then(function(ret){ console.log(ret.data) }) # 2.2 restful 形式传递参数 axios.get('http://localhost:3000/axios/123').then(function(ret){ console.log(ret.data) }) # 2.3 通过params 形式传递参数 axios.get('http://localhost:3000/axios', { params: { id: 789 } }).then(function(ret){ console.log(ret.data) }) #3 axios delete 请求传参 传参的形式和 get 请求一样 axios.delete('http://localhost:3000/axios', { params: { id: 111 } }).then(function(ret){ console.log(ret.data) }) # 4 axios 的 post 请求 # 4.1 通过选项传递参数 axios.post('http://localhost:3000/axios', { uname: 'lisi', pwd: 123 }).then(function(ret){ console.log(ret.data) }) # 4.2 通过 URLSearchParams 传递参数 var params = new URLSearchParams(); params.append('uname', 'zhangsan'); params.append('pwd', '111'); axios.post('http://localhost:3000/axios', params).then(function(ret){ console.log(ret.data) }) #5 axios put 请求传参 和 post 请求一样 axios.put('http://localhost:3000/axios/123', { uname: 'lisi', pwd: 123 }).then(function(ret){ console.log(ret.data) }) axios 全局配置# 配置公共的请求头 axios.defaults.baseURL = 'https://api.example.com'; # 配置 超时时间 axios.defaults.timeout = 2500; # 配置公共的请求头 axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; # 配置公共的 post 的 Content-Type axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; axios 拦截器 请求拦截器 请求拦截器的作用是在请求发送前进行一些操作 例如在每个请求体里加上token，统一做了处理如果以后要改也非常容易 响应拦截器 响应拦截器的作用是在接收到响应后进行一些操作 例如在服务器返回登录状态失效，需要重新登录的时候，跳转到登录页 # 1. 请求拦截器 axios.interceptors.request.use(function(config) { console.log(config.url) # 1.1 任何请求都会经过这一步 在发送请求之前做些什么 config.headers.mytoken = 'nihao'; # 1.2 这里一定要return 否则配置不成功 return config; }, function(err){ #1.3 对请求错误做点什么 console.log(err) }) #2. 响应拦截器 axios.interceptors.response.use(function(res) { #2.1 在接收响应做些什么 var data = res.data; return data; }, function(err){ #2.2 对响应错误做点什么 console.log(err) }) async 和 await async作为一个关键字放到函数前面 任何一个async函数都会隐式返回一个promise await关键字只能在使用async定义的函数中使用 ​ await后面可以直接跟一个 Promise实例对象 ​ await函数不能单独使用 async/await 让异步代码看起来、表现起来更像同步代码 # 1. async 基础用法 # 1.1 async作为一个关键字放到函数前面 async function queryData() { # 1.2 await关键字只能在使用async定义的函数中使用 await后面可以直接跟一个 Promise实例对象 var ret = await new Promise(function(resolve, reject){ setTimeout(function(){ resolve('nihao') },1000); }) // console.log(ret.data) return ret; } # 1.3 任何一个async函数都会隐式返回一个promise 我们可以使用then 进行链式编程 queryData().then(function(data){ console.log(data) }) #2. async 函数处理多个异步函数 axios.defaults.baseURL = 'http://localhost:3000'; async function queryData() { # 2.1 添加await之后 当前的await 返回结果之后才会执行后面的代码 var info = await axios.get('async1'); #2.2 让异步代码看起来、表现起来更像同步代码 var ret = await axios.get('async2?info=' + info.data); return ret.data; } queryData().then(function(data){ console.log(data) }) 图书列表案例1. 基于接口案例-获取图书列表 导入axios 用来发送ajax 把获取到的数据渲染到页面上 编号 名称 时间 操作 {{item.id}} {{item.name}} {{item.date }} 修改 | 删除 1. 导入axios 2 添加图书 获取用户输入的数据 发送到后台 渲染最新的数据到页面上 methods: { handle: async function(){ if(this.flag) { // 编辑图书 // 就是根据当前的ID去更新数组中对应的数据 this.books.some((item) => { if(item.id == this.id) { item.name = this.name; // 完成更新操作之后，需要终止循环 return true; } }); this.flag = false; }else{ # 1.1 在前面封装好的 handle 方法中 发送ajax请求 # 1.2 使用async 和 await 简化操作 需要在 function 前面添加 async var ret = await axios.post('books', { name: this.name }) # 1.3 根据后台返回的状态码判断是否加载数据 if(ret.status == 200) { # 1.4 调用 queryData 这个方法 渲染最新的数据 this.queryData(); } } // 清空表单 this.id = ''; this.name = ''; }, } 3 验证图书名称是否存在 添加图书之前发送请求验证图示是否已经存在 如果不存在 往后台里面添加图书名称 图书存在与否只需要修改submitFlag的值即可 watch: { name: async function(val) { // 验证图书名称是否已经存在 // var flag = this.books.some(function(item){ // return item.name == val; // }); var ret = await axios.get('/books/book/' + this.name); if(ret.status == 1) { // 图书名称存在 this.submitFlag = true; }else{ // 图书名称不存在 this.submitFlag = false; } } }, 4. 编辑图书 根据当前书的id 查询需要编辑的书籍 需要根据状态位判断是添加还是编辑 methods: { handle: async function(){ if(this.flag) { #4.3 编辑图书 把用户输入的信息提交到后台 var ret = await axios.put('books/' + this.id, { name: this.name }); if(ret.status == 200){ #4.4 完成添加后 重新加载列表数据 this.queryData(); } this.flag = false; }else{ // 添加图书 var ret = await axios.post('books', { name: this.name }) if(ret.status == 200) { // 重新加载列表数据 this.queryData(); } } // 清空表单 this.id = ''; this.name = ''; }, toEdit: async function(id){ #4.1 flag状态位用于区分编辑和添加操作 this.flag = true; #4.2 根据id查询出对应的图书信息 页面中可以加载出来最新的信息 # 调用接口发送ajax 请求 var ret = await axios.get('books/' + id); this.id = ret.id; this.name = ret.name; }, 5 删除图书 把需要删除的id书籍 通过参数的形式传递到后台 deleteBook: async function(id){ // 删除图书 var ret = await axios.delete('books/' + id); if(ret.status == 200) { // 重新加载列表数据 this.queryData(); } }
组件 (Component) 是 Vue.js 最强大的功能之一 组件可以扩展 HTML 元素，封装可重用的代 组件注册全局注册 Vue.component('组件名称', { }) 第1个参数是标签名称，第2个参数是一个选项对象 全局组件注册后，任何vue实例都可以用 组件基础用 <my-component></my-component> 组件注意事项 组件参数的data值必须是函数同时这个函数要求返回一个对象 组件模板必须是单个根元素 组件模板的内容可以是模板字符串 <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> <hello-world></hello-world> 局部注册 只能在当前注册它的vue实例中使用 <my-component></my-component> Vue 调试工具Vue组件之间传值父组件向子组件传值 父组件发送的形式是以属性的形式绑定值到子组件身上。 然后子组件用属性props接收 在props中使用驼峰形式，模板中需要使用短横线的形式字符串形式的模板中没有这个限制 {{pmsg}} <menu-item title='来自父组件的值'></menu-item> <menu-item :title='ptitle' content='hello'></menu-item> 子组件向父组件传值 子组件用$emit()触发事件 $emit() 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据 父组件用v-on 监听子组件的事件 {{pmsg}} <menu-item :parr='parr' @enlarge-text='handle($event)'></menu-item> 兄弟之间的传递 兄弟之间传递数据需要借助于事件中心，通过事件中心传递数据 提供事件中心 var hub = new Vue() 传递数据方，通过一个事件触发hub.$emit(方法名，传递的数据) 接收数据方，通过mounted(){} 钩子中 触发hub.$on()方法名 销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据 父组件 销毁事件 <test-tom></test-tom> <test-jerry></test-jerry> 组件插槽 组件的最大特性就是复用性，而用好插槽能大大提高组件的可复用能力 匿名插槽 <alert-box>有bug发生</alert-box> <alert-box>有一个警告</alert-box> <alert-box></alert-box> 具名插槽 具有名字的插槽 使用 中的 "name" 属性绑定元素 <base-layout> 标题信息 主要内容1 主要内容2 底部信息信息 </base-layout> <base-layout> 标题信息1 标题信息2 主要内容1 主要内容2 底部信息信息1 底部信息信息2 </base-layout> 作用域插槽 父组件对子组件加工处理 既可以复用子组件的slot，又可以使slot内容不一致 <fruit-list :list='list'> {{slotProps.info.name}} {{slotProps.info.name}} </fruit-list> 购物车案例1. 实现组件化布局 把静态页面转换成组件化模式 把组件渲染到页面上 <my-cart></my-cart> 2、实现 标题和结算功能组件 标题组件实现动态渲染 从父组件把标题数据传递过来 即 父向子组件传值 把传递过来的数据渲染到页面上 结算功能组件 从父组件把商品列表list 数据传递过来 即 父向子组件传值 把传递过来的数据计算最终价格渲染到页面上 <my-cart></my-cart> 3. 实现列表组件删除功能 从父组件把商品列表list 数据传递过来 即 父向子组件传值 把传递过来的数据渲染到页面上 点击删除按钮的时候删除对应的数据 给按钮添加点击事件把需要删除的id传递过来 子组件中不推荐操作父组件的数据有可能多个子组件使用父组件的数据 我们需要把数据传递给父组件让父组件操作数据 父组件删除对应的数据 <my-cart></my-cart> 4. 实现组件更新数据功能 上 将输入框中的默认数据动态渲染出来 输入框失去焦点的时候 更改商品的数量 子组件中不推荐操作数据 把这些数据传递给父组件 让父组件处理这些数据 父组件中接收子组件传递过来的数据并处理 <my-cart></my-cart> 5. 实现组件更新数据功能 下 子组件通过一个标识符来标记对用的用户点击 + - 或者输入框输入的内容 父组件拿到标识符更新对应的组件 Document <my-cart></my-cart>
表单基本操作 获取单选框中的值 通过v-model 男 女 获取复选框中的值 通过v-model 和获取单选框中的值一样 复选框 checkbox 这种的组合时 data 中的 hobby 我们要定义成数组 否则无法实现多选 爱好： 篮球 唱歌 写代码 获取下拉框和文本框中的值 通过v-model 职业： 请选择职业... 教师 软件工程师 律师 表单修饰符 .number 转换为数值 注意点： 当开始输入非数字的字符串时，因为Vue无法将字符串转换成数值 所以属性值将实时更新成相同的字符串。即使后面输入数字，也将被视作字符串。 .trim 自动过滤用户输入的首尾空白字符 只能去掉首尾的 不能去除中间的空格 .lazy 将input事件切换成change事件 .lazy 修饰符延迟了同步更新属性值的时机。即将原本绑定在 input 事件的同步逻辑转变为绑定在 change 事件上 在失去焦点 或者 按下回车键时才更新 自定义指令 内置指令不能满足我们特殊的需求 Vue允许我们自定义指令 Vue.directive 注册全局指令 Vue.directive 注册全局指令 带参数 自定义指令局部指令 局部指令，需要定义在 directives 的选项 用法和全局用法一样 局部指令只能在当前组件里面使用 当全局指令和局部指令同名时以局部指令为准 计算属性 computed 模板中放入太多的逻辑会让模板过重且难以维护 使用计算属性可以让模板更加的简洁 计算属性是基于它们的响应式依赖进行缓存的 computed比较适合对多个变量或者对象进行处理后返回一个结果值，也就是数多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化 {{reverseString}} {{reverseString}} {{reverseMessage()}} {{reverseMessage()}} 侦听器 watch 使用watch来响应数据的变化 一般用于异步或者开销较大的操作 watch 中的属性 一定是data 中 已经存在的数据 当需要监听一个对象的改变时，普通的watch方法无法监听到对象内部属性的改变，只有data中的数据才能够监听到变化，此时就需要deep属性对对象进行深度监听 名： 姓： {{fullName}} 过滤器 Vue.js允许自定义过滤器，可被用于一些常见的文本格式化。 过滤器可以用在两个地方：双花括号插值和v-bind表达式。 过滤器应该被添加在JavaScript表达式的尾部，由“管道”符号指示 支持级联操作 过滤器不改变真正的data，而只是改变渲染的结果，并返回过滤后的版本 全局注册时是filter，没有s的。而局部过滤器是filters，是有s的 测试数据 过滤器中传递参数 生命周期 事物从出生到死亡的过程 Vue实例从创建 到销毁的过程 ，这些过程中会伴随着一些函数的自调用。我们称这些函数为钩子函数 常用的 钩子函数 beforeCreate 在实例初始化之后，数据观测和事件配置之前被调用 此时data 和 methods 以及页面的DOM结构都没有初始化 什么都做不了 created 在实例创建完成后被立即调用此时data 和 methods已经可以使用 但是页面还没有渲染出来 beforeMount 在挂载开始之前被调用 此时页面上还看不到真实数据 只是一个模板页面而已 mounted el被新创建的vm.$el替换，并挂载到实例上去之后调用该钩子。 数据已经真实渲染到页面上 在这个钩子函数里面我们可以使用一些第三方的插件 beforeUpdate 数据更新时调用，发生在虚拟DOM打补丁之前。 页面上数据还是旧的 updated 由于数据更改导致的虚拟DOM重新渲染和打补丁，在这之后会调用该钩子。 页面上数据已经替换成最新的 beforeDestroy 实例销毁之前调用 destroyed 实例销毁后调用 数组变异方法 在 Vue 中，直接修改对象属性的值无法触发响应式。当你直接修改了对象属性的值，你会发现，只有数据改了，但是页面内容并没有改变 变异数组方法即保持数组方法原有功能不变的前提下对其进行功能拓展 push() 往数组最后面添加一个元素，成功返回当前数组的长度 pop() 删除数组的最后一个元素，成功返回删除元素的值 shift() 删除数组的第一个元素，成功返回删除元素的值 unshift() 往数组最前面添加一个元素，成功返回当前数组的长度 splice() 有三个参数，第一个是想要删除的元素的下标（必选），第二个是想要删除的个数（必选），第三个是删除 后想要在原位置替换的值 sort() sort() 使数组按照字符编码默认从小到大排序,成功返回排序后的数组 reverse() reverse() 将数组倒序，成功返回倒序后的数组 替换数组 不会改变原始数组，但总是返回一个新数组 filter filter() 方法创建一个新的数组，新数组中的元素是通过检查指定数组中符合条件的所有元素。 concat concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组 slice slice() 方法可从已有的数组中返回选定的元素。该方法并不会修改数组，而是返回一个子数组 动态数组响应式数据 Vue.set(a,b,c) 让 触发视图重新更新一遍，数据动态起来 a是要更改的数据 、 b是数据的第几项、 c是更改后的数据 图书列表案例 静态列表效果 基于数据实现模板效果 处理每行的操作按钮 1、 提供的静态数据 数据存放在vue 中 data 属性中 var vm = new Vue({ el: '#app', data: { books: [{ id: 1, name: '三国演义', date: '' },{ id: 2, name: '水浒传', date: '' },{ id: 3, name: '红楼梦', date: '' },{ id: 4, name: '西游记', date: '' }] } }); var vm = new Vue({ el: '#app', data: { books: [{ id: 1, name: '三国演义', date: '' },{ id: 2, name: '水浒传', date: '' },{ id: 3, name: '红楼梦', date: '' },{ id: 4, name: '西游记', date: '' }] } }); 2、 把提供好的数据渲染到页面上 利用 v-for循环 遍历 books 将每一项数据渲染到对应的数据中 {{item.id}} {{item.name}} {{item.date}} 修改 | 删除 3、 添加图书 通过双向绑定获取到输入框中的输入内容 给按钮添加点击事件 把输入框中的数据存储到 data 中的 books 里面 图书管理 编号： 名称： 提交 4 修改图书-上 点击修改按钮的时候 获取到要修改的书籍名单 4.1 给修改按钮添加点击事件， 需要把当前的图书的id 传递过去 这样才知道需要修改的是哪一本书籍 把需要修改的书籍名单填充到表单里面 4.2 根据传递过来的id 查出books 中 对应书籍的详细信息 4.3 把获取到的信息填充到表单 图书管理 编号： 名称： 提交 编号 名称 时间 操作 {{item.id}} {{item.name}} {{item.date}} 修改 | 删除 5 修改图书-下 5.1 定义一个标识符， 主要是控制 编辑状态下当前编辑书籍的id 不能被修改 即 处于编辑状态下 当前控制书籍编号的输入框禁用 5.2 通过属性绑定给书籍编号的 绑定 disabled 的属性 flag 为 true 即为禁用 5.3 flag 默认值为false 处于编辑状态 要把 flag 改为true 即当前表单为禁用 5.4 复用添加方法 用户点击提交的时候依然执行 handle 中的逻辑如果 flag为true 即 表单处于不可输入状态 此时执行的用户编辑数据数据 图书管理 编号： 名称： 提交 编号 名称 时间 操作 {{item.id}} {{item.name}} {{item.date}} 修改 | 删除 6 删除图书 6.1 给删除按钮添加事件 把当前需要删除的书籍id 传递过来 6.2 根据id从数组中查找元素的索引 6.3 根据索引删除数组元素 {{item.id}} {{item.name}} {{item.date}} 修改 | 删除 常用特性应用场景1 过滤器 Vue.filter 定义一个全局过滤器 {{item.id}} {{item.name}} 修改 | 删除 2 自定义指令 让表单自动获取焦点 通过Vue.directive 自定义指定 3 计算属性 通过计算属性计算图书的总数 图书的总数就是计算数组的长度 图书总数： {{total}}
题目描述 点击tab栏 内容区域显示对应的内容 如 点击 SECTION 1 则 内容区域显示 对应 SECTION 1 的内容 同时当前 SECTION的字体颜色变成蓝色 训练目标 能够理解vue 中的数据渲染 能够理解 v-for, v-if , v-bind , v-click 的使用 能够理解 vue 中调用函数的时候传递参数 训练提示 提供的数据如下1、 数据 list: [{ id: 1, title: 'Section 1', content: 'content1' }, { id: 2, title: 'Section 2', content: 'content2' }, { id: 3, title: 'Section 3', content: 'content3' }, { id: 4, title: 'Section 4', content: 'content4' }, { id: 5, title: 'Section 5', content: 'content5' }, { id: 6, title: 'Section 6', content: 'content6' }] 2、 HTML 结构如下 Section 1 Section 2 Section 3 Section 1 content1 Section 2 content2 Section 3 content3 Section 4 content4 Section 5 content5 Section 6 content6 Section 4 Section 5 Section 6 第一步： 将 list 中的数据title 渲染到 左侧和 右侧的tab栏中 注意： 左右各渲染3条数据 第二步： 将 list 中的数据title 和 content 渲染到 内容区域 第三步： 给左侧的tab栏中的li绑定事件 实现动态切换active 类名 注意： 给点击的当前li 添加类名 active 即可让当前的li字体颜色改变 (类名是 active的样式已经在CSS中提前定义好 ) 其他 li 需要移除类名 active 第四步： 拿到当前点击li的索引 让 内容区域中 对应索引类名是 tab-pane 的 div 显示 注意： 给 类名是 tab-pane 的 div 添加 类名 active 即可让当前div 显示出来 (类名是 active的样式已经在CSS中提前定义好 ) 其他 tab-pane 的 div 需要移除类名 active 第五步： 给右侧的tab栏中的li绑定事件 实现动态切换active 类名 注意： 给点击的当前li 添加类名 active 即可让当前的li字体颜色改变 (类名是 active的样式已经在CSS中提前定义好 ) 第六步： 拿到当前点击li的索引 让 内容区域中 对应索引类名是 tab-pane 的 div 显示 注意： 这里需要注意索引问题： 点击右侧第一个div 的时候 需要让内容区域中的第 4个 div 显示出来 点击右侧第2个div 的时候 需要让内容区域中的第 5个 div 显示出来 操作步骤 HTML Section 1 Section 2 Section 3 Section 1 content1 Section 2 content2 Section 3 content3 Section 4 content4 Section 5 content5 Section 6 content6 Section 4 Section 5 Section 6 CSS data 中的数据 list: [{ id: 1, title: 'Section 1', content: 'content1' }, { id: 2, title: 'Section 2', content: 'content2' }, { id: 3, title: 'Section 3', content: 'content3' }, { id: 4, title: 'Section 4', content: 'content4' }, { id: 5, title: 'Section 5', content: 'content5' }, { id: 6, title: 'Section 6', content: 'content6' }] ​
Vue (读音 /vjuː/，类似于 view) 是一套用于构建用户界面的渐进式框架 vue 的核心库只关注视图层，不仅易于上手，还便于与第三方库或既有项目整合 使用Vue将helloworld 渲染到页面上指令 本质就是自定义属性 Vue中指定都是以 v- 开头 v-cloak 防止页面加载时出现闪烁问题 {{msg}} v-text v-text指令用于将数据填充到标签中，作用于插值表达式类似，但是没有闪动问题 如果数据中有HTML标签会将html标签一并输出 注意：此处为单向绑定，数据对象上的值改变，插值会发生变化；但是当插值发生变化并不会影响数据对象的值 {{msg}} v-html 用法和v-text 相似 但是他可以将HTML片段填充到标签中 可能有安全问题, 一般只在可信任内容上使用 v-html，永不用在用户提交的内容上 它与v-text区别在于v-text输出的是纯文本，浏览器不会对其再进行html解析，但v-html会将其当html标签解析后输出。 {{message}} v-pre 显示原始信息跳过编译过程 跳过这个元素和它的子元素的编译过程。 一些静态的内容不需要编译加这个指令可以加快渲染 {{ this will not be compiled }} {{msg}} v-once 执行一次性的插值【当数据改变时，插值处的内容不会继续更新】 {{ msg}} 双向数据绑定 当数据发生变化的时候，视图也就发生变化 当视图发生变化的时候，数据也会跟着同步变化 v-model v-model是一个指令，限制在 、 、 、components中使用 {{msg}} 当输入框中内容改变的时候， 页面上的msg 会自动更新 mvvm MVC 是后端的分层开发概念； MVVM是前端视图层的概念，主要关注于 视图层分离，也就是说：MVVM把前端的视图层，分为了 三部分 Model, View , VM ViewModel m model 数据层 Vue 中 数据层 都放在 data 里面 v view 视图 Vue 中 view 即 我们的HTML页面 vm （view-model） 控制器 将数据和视图层建立联系 vm 即 Vue 的实例 就是 vm v-on 用来绑定事件的 形式如：v-on:click 缩写为 @click; v-on事件函数中传入参数 {{num}} 点击1 点击2 事件修饰符 在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。 Vue 不推荐我们操作DOM 为了解决这个问题，Vue.js 为 v-on 提供了事件修饰符 修饰符是由点开头的指令后缀来表示的 ... 使用修饰符时，顺序很重要；相应的代码会以同样的顺序产生。因此，用 v-on:click.prevent.self 会阻止所有的点击，而 v-on:click.self.prevent 只会阻止对元素自身的点击。 按键修饰符 在做项目中有时会用到键盘事件，在监听键盘事件时，我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符 常用的按键修饰符 .enter => enter键 .tab => tab键 .delete (捕获“删除”和“退格”按键) => 删除键 .esc => 取消键 .space => 空格键 .up => 上 .down => 下 .left => 左 .right => 右 自定义按键修饰符别名 在Vue中可以通过config.keyCodes自定义按键修饰符别名 预先定义了keycode 116（即F5）的别名为f5，因此在文字输入框中按下F5，会触发prompt方法 v-bind v-bind 指令被用来响应地更新 HTML 属性 v-bind:href 可以缩写为 :href; 绑定对象 我们可以给v-bind:class 一个对象，以动态地切换class。 注意：v-bind:class指令可以与普通的class特性共存 1、 v-bind 中支持绑定一个对象 如果绑定的是一个对象 则 键为 对应的类名 值 为对应data中的数据 学习Vue 学习Node 学习React 对象语法 <sript> var vm= new Vue({ el:'.box', data:{ isColor:true, isSize:true， activeColor:"red", activeSize:"25px", } }) </sript> 绑定class2、 v-bind 中支持绑定一个数组 数组中classA和 classB 对应为data中的数据 这里的classA 对用data 中的 classA 这里的classB 对用data 中的 classB 学习Vue 学习Node 学习React 绑定对象和绑定数组 的区别 绑定对象的时候 对象的属性 即要渲染的类名 对象的属性值对应的是 data 中的数据 绑定数组的时候数组里面存的是data 中的数据 绑定style 绑定样式对象 ' 内联样式 分支结构v-if 使用场景 1- 多个元素 通过条件判断展示或者隐藏某个元素。或者多个元素 2- 进行两个视图之间的切换 如果flag为true则显示,false不显示! ---------------------------------------------------------- A B C Not A/B/C v-show 和 v-if的区别 v-show本质就是标签display设置为none，控制隐藏 v-show只编译一次，后面其实就是控制css，而v-if不停的销毁和创建，故v-show性能更好一点。 v-if是动态的向DOM树内添加或者删除DOM元素 v-if切换有一个局部编译/卸载的过程，切换过程中合适地销毁和重建内部的事件监听和子组件 循环结构v-for 用于循环的数组里面的值可以是对象，也可以是普通元素 {{ item.message }} 不推荐同时使用 v-if 和 v-for 当 v-if 与 v-for 一起使用时，v-for 具有比 v-if 更高的优先级。 {{v + '---' + k + '---' + i}} key 的作用 key来给每个节点做一个唯一标识 key的作用主要是为了高效的更新虚拟DOM ... 案例选项卡1、 HTML 结构` apple orange lemon ` 2、 提供的数据 list: [{ id: 1, title: 'apple', path: 'img/apple.png' }, { id: 2, title: 'orange', path: 'img/orange.png' }, { id: 3, title: 'lemon', path: 'img/lemon.png' }] 3、 把数据渲染到页面 把tab栏 中的数替换到页面上 把 data 中 title 利用 v-for 循环渲染到页面上 把 data 中 path利用 v-for 循环渲染到页面上 {{item.title}} 4、 给每一个tab栏添加事件,并让选中的高亮 4.1 、让默认的第一项tab栏高亮 tab栏高亮 通过添加类名active 来实现 （CSS active 的样式已经提前写好） 在data 中定义一个 默认的 索引 currentIndex 为 0 给第一个li 添加 active 的类名 通过动态绑定class 来实现 第一个li 的索引为 0 和 currentIndex 的值刚好相等 currentIndex === index 如果相等 则添加类名 active 否则 添加 空类名 4.2 、让默认的第一项tab栏对应的div 显示 实现思路 和 第一个 tab 实现思路一样 只不过 这里控制第一个div 显示的类名是 current {{item.title}} 4.3 、点击每一个tab栏 当前的高亮 其他的取消高亮 给每一个li添加点击事件 让当前的索引 index 和 当前 currentIndex 的 值 进项比较 如果相等 则当前li 添加active 类名 当前的 li 高亮 当前对应索引的 div 添加 current 当前div 显示 其他隐藏 {{item.title}}