青椒肉丝加点糖
IP:
0关注数
0粉丝数
0获得的赞
工作年
编辑资料
链接我:

创作·89

全部
问答
动态
项目
学习
专栏
青椒肉丝加点糖

rollup实战(一)之rollup搭建组件库

前言本篇文章分享如何和用 rollup 来构建一个组件库,以及使用vite搭建一个测试环境rollup 在构建组件库上,相较于 webpack 有什么优点呢rollup 基于 esm 模块作为输入模式,在构建组件库时具有更快的构建速度、更简洁的配置,更好的代码质量和更低的内存占用等优点。这些优点让 rollup 成为构建组件库的首选下面我们来看看如何使用 rollup 构建一个组件库准备两个组件首先准备两个组件,Button 和 InputButtonimport { useState } from "react" const Button = (props: { content: string }) => { const [count, setCount] = useState(0); return <div><button onClick={() => setCount(count + 1)}>count: {count}</button> <div>{props.content}</div> </div> } export default Button;Inputconst Input = () => { return <div> <span>input anything: </span> <input></input> </div> } export default Input;代码都很简单,都是非常基础的代码然后在 src 根目录下的 index 文件,将这些文件都导入并导出import Button from "./Button"; import Input from "./Input" // 导出组件文件中的非default导出 export * from './Button'; export * from './Input'; // 导出组件本身 export { Button, Input }组件准备好了,下面就开始打包了配置 rollup先在项目的根目录中创建一个 rollup 配置文件:rollup.config.js/**@type {import('rollup').RollupOptions} */ module.exports = { input: "./src/index.tsx", output: { dir: "./dist", format: "esm", sourcemap: true, }, plugins: [ //... ], external: ["react", "react-dom","react/jsx-runtime"], };小技巧:如果希望在 js 文件中,还可以获得像 ts 的编译器提示,可以使用 jsDoc,像上面的/**@type */配置中,需要指出构建的入口./src/index.tsx,以及构建产物的目录./dist,格式,是否生成 sourcemap 等信息。rollup 不仅可以打包成 esm 格式,还可以打包成 esm 格式,umd 格式,不过对于组件库而言,其应用场景是在 node 环境中的其他项目中引入,所以一般是打包成 esm。不过为了多环境的支持性,会构建 esm 和 umd 两种类型的产物plugins 中就是放插件,添加额外功能的地方了。external 表示哪些包不放进构建产物中,若它的值是["react", "react-dom"],那就表示 react 和 react-dom, 以及 react 运行时依赖react/jsx-runtime,均不打包进构建产物中添加插件rollup 作为一个构建工具,只提供一些非常基础的能力,像 commonjs 模块解析,json 解析,ts 解析,css 解析等,都不支持。好在 rollup 提供了方便简单的插件机制,并且有非常多的生命周期 hook,使得开发人员为其添加额外的功能颇为方便1先添加@rollup/plugin-commonjs, 赋予 rollup 加载第三方依赖的功能,添加@rollup/plugin-commonjs, 赋予rollup将cjc模块转成esm模块的能力npm i @rollup/plugin-commonjs @rollup/plugin-commonjs -D2添加@rollup/plugin-typescript, 赋予rolllup解析typescript的能力,还要添加相关的依赖: typescriptnpm i typescript @rollup/plugin-commonjs -D因为需要用 typescript 生成类型文件,所以还需要配置 ts 的配置文件:tsconfig.json{ "compilerOptions": { "rootDir": "./src", "baseUrl": "./", "jsx": "react-jsx", "declaration": true, "emitDeclarationOnly": true, "outDir": "./dist/types", "lib": [ "es2020" ] } }这里有几个和构建有关的,我需要重点提一下:declaration 表示生成类型文件,emitDeclarationOnly 表示只生成类型文件。因为 rollup 是借助 babel 做编译,所以只需要 ts 提供类型文件的输出即可outDir 的值是./dist/types表示 tsc 的编译产物放到当前目录下的 dist 文件夹下的 types 目录rootDIr,默认是 src,即包含所有的 ts 文件。也可以手动指定。那rootDIr是用来干什么的呢?rootDir 是和 outDir 结合起来用的。如果 rootDir 的值是./src,那么构建之后的产物就是这样的:即 src 下面的文件结构直接铺在 types 文件夹下面那如果 rootDir 的值是./,就会变成这样:即 types 文件夹下面还嵌套着一层 src。这就是 rootDir 的作用使用了@rollup/plugin-typescript,在 rollup build 的时候,就会使用 tsc 对文件进行编译,所以当我仅执行了 rollup -c 后,types 会自动产生3添加@rollup/plugin-babel, 赋予 rollup 可以解析 jsx,降级 js 语法的能力。还要添加相关的依赖:@babel/core, @babel/preset-react。因为是react 组件库,所以还需要安装 react , react-dom,@types/react, @types/react-domnpm i react react-dom @types/react @types/react-dom -D npm i @babel/core @babel/preset-react -D npm i @rollup/plugin-babel -D如果需要使用 babel 对 js 语法做降级处理,就需要安装@babel/preset-env, @babel/plugin-transform-runtime4添加rollup-plugin-postcss, postcss, 赋予 rollup 解析 css,scss,sass 的能力npm i rollup-plugin-postcss postcss -D完善 rollup 配置需要的功能都差不多了,完善下 rollup 配置文件吧const resolve = require("@rollup/plugin-node-resolve"); const postcss = require("rollup-plugin-postcss"); const typescript = require("@rollup/plugin-typescript"); const commonjs = require("@rollup/plugin-commonjs"); const { babel } = require("@rollup/plugin-babel"); /**@type {import('rollup').RollupOptions} */ module.exports = { input: "./src/index.tsx", output: { dir: "./dist", format: "esm", sourcemap: true, }, plugins: [ resolve(), commonjs(), postcss(), typescript(), babel({ presets: ["@babel/preset-react"], exclude: /nodex_module/, }), ], external: ["react", "react-dom"], };配置文件做好了,下面测试一下,看看 rollup 构建是什么样子先添加一个 npm script// package.json { "scripts": { "build": "rollup -c", } }-c的意思是,执行 rollup 时,使用 rollup 配置文件中的配置执行npm run build构建好了,花费 1.1s。 因为组件简单,就很快这是构建产物的结构:有 types 类型文件,还有 index.js 和对应的 index.js.map再看看 index.js 里面长什么样子:两个组件都被置于 index 文件中,并且格式是 esm,符合预期不 bundle 构建不过传统的 esm 都是不 bundle 的,也就是不打包成单个文件的,再改改 rollup.config.js:{ output: { dir: "./dist", format: "esm", sourcemap: true, //rollup只编译,不打包 preserveModules: true, }, }再次执行npm run build文件结构变成了这个样子:index.js 的内容:好了,构建文件做好了,该怎么测试它的可用性呢?使用 vite 搭建测试环境测试的思路是使用 vite 新建一个 react demo 项目,然后用 npm link 的方式来测试上面的构建产物mkdir use-rollup cd use-rolllup npm init -y npm i vite react react-dom @types/react @types/react-dom @vitejs/plugin-react typescript先创建一个测试项目的文件夹,然后在其中安装必要的依赖配置 vite.config.js 文件import viteReact from "@vitejs/plugin-react"; /**@type {import('vite').UserConfig} */ export default { plugins: [viteReact()], server: { port: 8080, open: "/", }, }; vite 自身支持丰富的功能,所以这里仅需要 react 插件即可。还另外配置了本地服务器配置 tsconfig.json{ "compilerOptions": { "jsx": "react-jsx", } }因为需要用到 react,所以这里配置不用引入 react 的 ts 配置,其他 ts 配置用默认的就好编写 index.tsximport ReactDOM from 'react-dom/client' import { Button } from 'rollup-build' const App = () => { return <div> App </div> } ReactDOM.createRoot(document.getElementById('root')).render(<App />)准备一个 index.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=, initial-scale=1.0" /> <title>use-rollup</title> <script type="module" src="./src/index.tsx" defer></script> </head> <body> <div id="root"></div> </body> </html>将 index.html 作为 vite 启动的入口文件好了,到这里所有的东西都准备好了,这是现在的文件结构:启动项目先添加一个 npm script:"scripts": { "start": "vite" },执行npm run start:启动成功,修改几个字符看看页面也刷新了。项目没问题,下面开始测试构建产物测试构建产物首先要做到的是修改组件库项目的 package 的 main 和 types 文件指向:{ "main": "./dist/index.js", "types": "./dist/types", }mian 和 types 都指向 dist 文件夹,也就是构建产物的文件夹然后在组件库项目根目录终端执行: npm link再在 demo 目录执行npm link rollup-buildlink 成功之后,就可以在 index.tsx 中引入对应的组件保存,刷新页面:测试成功,没有问题优化测试的体验在使用 npm link 测试后,发现了个问题,Button 的 content 的属性名不对,应该是 contents,少了个 s,这时候就要修改组件库的代码了修改组件库代码之后,还需要 build,构建之后才能在 demo 项目里看见变化。那这个体验就很糟糕了,有没有什么办法可以像 vite 本地开发服务器一样,一旦文件保存,就可以在测试端看见变化呢?当然是有办法的rollup 支持 watch 模式,一旦文件变动,就会自动地单独重新构建这个文件给组件库添加一个新的 npm script:{ "build:watch": "rollup -c -w" }-w的意思就是开启 watch下面来试试:修改 Button 的属性const Button = (props: { contents: string }) => { const [count, setCount] = useState(0); return <div><button onClick={() => setCount(count + 1)}>count: {count}</button> <div>{props.contents}</div> </div> }ctrl + s 保存后,主要看看这两个文件有没有变化:这是构建之后的 Button/index.js这是 types/Button/index.d.ts均已发生变化!!很不错,看看 demo 项目中的 src/index.tsx:ts 已经提示报错了总结:这篇文章分享了如何用 rollup 来构建一个组件库。介绍了 rollup 配置的基本用法以及相关的插件。为了测试构建产物,还用 vite 来搭建一个 demo 环境,使用 npm link 来测试构建产物的可用性和正确性。最后为了测试的体验,借助了 rollup 的 watch 模式,可以在监听到文件变化后,自动重新构建。
0
0
0
浏览量573
青椒肉丝加点糖

rollup实战(四)之测试不同模块的构建产物

前言上篇文章使用 rollup 对组件库进行构建,构建产物有三种模块,分别是 esm 模块,umd 模块,iife 模块。具体构建过程可以看这篇文章:👊rollup实战(三)之从开源角度去优化一个组件库这篇文章分享的是如何对不同模块的构建产物进行测试下面开始回顾先来回顾组件库的内容组件库中,准备了两个组件,Button,Input样式也是随便写的,长下面这样:构建产物放在了 dist 文件夹下面packagejson 中也对引入路径做了设置:{ "main": "./dist/umd/rollup-build.js", "types": "./dist/types", "module": "./dist/es/index.js", }如果调用方是在 esm 模式下引入的,就会得到 es 文件夹下面的文件;如果是在 commonjs 模式下引入的,就会得到 umd 文件夹下面的文件。iife 构建文件没有准备的入口,因为这个模块的使用场景是在浏览器中的 script,测试的时候直接 copy 这个文件到 html 文件中就可以了测试 ESM 模块现来测试 ESM 模块的构建产物在之前的文章中提到过,在另外一个项目中,通过 npm link 的方式链接到本地组件库项目,然后在代码中使用 import 语句就可以调用构建产物中的组件了因为是 import 引入的,所以会被当成是 esm 模式导入,所以测试到的文件就是 dist/es 文件夹下面的具体过程可以看这篇文章:👊rollup实战(一)之rollup搭建组件库测试 UMD 模块UMD 模块可以在 commonjs 模块中使用,也可以直接在 script 的场景直接引入。如果使用 require 的方式引入组件库组件,就会得到dist/umd下的文件,这是测试 commonjs 场景的思路。对于 script 的场景,就需要 copy 构建产物的路径到 html 文件中了。具体操作可以往下看commonjs 模块中使用在 esm 模块的测试基础上,添加一个 require 引入组件的方式就可以了。准备一个 CustomButton.jsx 文件:const { Button } = require("rollup-build"); const CustomButton = () => { return ( <div> <Button contents='custom Button' /> </div> ); }; module.exports = CustomButton;可以看到这里使用的是 commonjs 语法。然后在入口文件中引入它:// index.tsx import * as ReactDOM from 'react-dom/client' import CustomButton from './CustomButton.jsx' const App = () => { return <div> App App App <CustomButton /> </div> } ReactDOM.createRoot(document.getElementById('root')).render(<App />)保存,刷新浏览器:发现报错了,查了下,是因为 vite 并不支持 commonjs 模块的文件解析,所以需要加上一个插件://vite.config.js import commonjs from "vite-plugin-commonjs"; export default { plugins: [viteReact(), commonjs()], } 保存,再刷新浏览器:组件出现了,但是没有预期中的样式,按钮应该是蓝色,而不是原生的灰色。原来组件库在构建的时候,将 css 单独构建成一个文件了,在调用方需要单独引入。这一点和 antd 一致。//index.tsx import * as ReactDOM from 'react-dom/client' import CustomButton from './CustomButton.jsx' //引入样式文件 import "rollup-build/dist/es/rollup-build.css" const App = () => { return <div> App App App <CustomButton /> </div> } ReactDOM.createRoot(document.getElementById('root')).render(<App />) 保存,再刷新浏览器:组件正常显示,umd 模块下的 commonjs 导入没有问题搞定🤝script 场景下使用script 场景测试需要在 vite buid 之后。vite build 过程中,将 react,react-dom, 组件库 rollup-build全都 external 掉,不打包,然后在 build 之后的 index.html 中,额外将 react,react-dom,rolluo-build 都用 script 导入,最后用浏览器打开 index.html,就知道 umd 模块的构建产物在 script 场景下是否可以正常使用了组件库 package.name 是 rollup-buildexternal 需要vite-plugin-externals插件,修改下 vite 配置文件:import viteReact from "@vitejs/plugin-react"; import commonjs from "vite-plugin-commonjs"; import { viteExternalsPlugin } from "vite-plugin-externals"; /**@type {import('vite').UserConfig} */ export default { plugins: [ viteReact(), commonjs(), viteExternalsPlugin({ react: "React", "react-dom": "ReactDOM", "rollup-build": "RB", }) ], server: { port: 8080, open: "/", }, }; 配置vite-plugin-externals,将三个库都 external 出去,并且设置好每个库在全局环境下的变量名先准备一个基础 vite 项目,并且支持 react 的解析组件库在构建时,设定的全局变量名就是 RB添加一个 npm script{ "scripts": { "build": "vite build", }, }执行npm run build花费了 188ms,生成了三个文件,一个 html,一个 js,一个 css这是 html 中的内容:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>use-rollup</title> <script type="module" crossorigin src="./assets/index-8wqCi6qd.js"></script> <link rel="stylesheet" crossorigin href="./assets/index--sNeZMP7.css" /> </head> <body> <div id="root"></div> </body> </html> vite 为我们自动引入了 build 好的文件 js 和 css 文件,下面我们需要手动将 external 的库引入进 html 中。我事先将三个库的 js 文件放到了 src 同机目录下的 pro 目录中:react 和 react-dom 是从 node_modules 中拷贝来的,rollup-build 也是从 dist/umd中拷贝过来的。将这三个文件引入进 html 中:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>use-rollup</title> <script type="module" crossorigin src="./assets/index-8wqCi6qd.js"></script> <link rel="stylesheet" crossorigin href="./assets/index--sNeZMP7.css" /> </head> <body> <div id="root"></div> <!-- 添加额外的script文件 --> <script src="../prod/react.development.js"></script> <script src="../prod/react-dom.development.js"></script> <script src="../prod/rollup-build.js"></script> </body> </html> 然后启动一个本地服务器,打开这个 html 文件:显示正常,没有问题。到这里,测试 umd 模块的两个场景都已测试成功🏅iife 模块测试 iife 模块,和 umd 模块的 script 场景测试过程相同,就不赘述了测试体验优化不过,script 场景的测试有些麻烦。第一点:需要手动 copy 文件,和手动修改 index.html 文件,这不太友好。我们可以借助 vite 插件,来自动生成一个动态的 html,生成 html 可以自定义插入任何 script 脚本第二点:external 只适应于build 模式,而不能用于普通的 dev 模式,所以两者的配置文件是不相同,需要分开来针对上面两点,我们可以在项目根目录中创建一个新的配置文件 vite.config.test.js:// vite.config.test.js // 导出普通的配置文件 import viteConfig from "./vite.config.js"; import { viteExternalsPlugin } from "vite-plugin-externals"; import { createHtmlPlugin } from "vite-plugin-html"; // 生成需要插入的script脚本 const getscript = () => { const sources = ["../prod/react.development.js", "../prod/react-dom.development.js", "../prod/rollup-build.js"]; return sources .map((item) => { return `<script src='${item}'></script>`; }) .join("\n"); }; // 在原先的基础之上添加两个plugin viteConfig.plugins.push( viteExternalsPlugin({ react: "React", "react-dom": "ReactDOM", "rollup-build": "RB", }), // 基于public/index.html, 将其作为tamplate createHtmlPlugin({ minify: false, entry: "../src/index.tsx", template: "public/index.html", inject: { data: { injectScript: getscript(), }, }, }) ); export default viteConfig; 新配置文件基于原先的普通配置文件,在基础上添加了两个插件,用作测试 script 场景下的构建产物createHtmlPlugin 插件基于public/index.html,这个 html 文件需要单独准备,其中支持 ejs 语法。该插件正是基于 ejs 语法来做插入 script 脚本操作的public/index.html的内容:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>use-rollup</title> </head> <body> <div id="root"></div> <%- injectScript %> </body> </html>总结:这篇文章分享了如何测试组件库的构建产物,该测试方法不仅适用于 rollup 构建的库,还适
0
0
0
浏览量387
青椒肉丝加点糖

rollup实战(三)之从开源角度去优化一个组件库

前言承接上文,我们用 rollup 搭建了一个组件库 rollup-build,但还有些需要优化的地方:构建速度不够快构建的产物只有 esm 模块,没有 umd 模块,iife 模块本篇文章内容是基于上篇文章的内容,所以了解上篇文章的内容会对阅读更有帮助传送门:👊rollup实战(二)之用vite搭建rollup组件库的开发环境构建产物准备了三种模块,每种模块都有它的作用:esm 用来支持 esmodule 环境的, 在大多数的开发环境,都是 esmodule,并且 esm 模式支持 tree shaking。所以 esm 是必要的umd 模块,支持三种模式的引入,一种是 commonjs,一种是 script,还有一种是 amd; 对于 commonjs 在一些 node 环境中是必要的。script 的场景就是在消费端将rollup-build external 的时候,就需要用 script 导入了。amd 的场景我还没遇到过对于 commonjs,我还没有遇到要用 commojs 来开发前端页面的,但是很多库都支持,咱也不能落后不是。 可能一些构建工具在引入库的时候就是 commonjs? 不过对于 script,我倒认为需求场景比较多iife 模块,iife 模块也是 script 导入使用,但相较于 umd,我更倾向于认为 iife是适配低版本浏览器,只支持 es5,甚至更低的那种。在 script 引入组件库rollup-build的依赖(ps: react, reactd-dom),然后引入组件库rollup-build,就可以直接使用。要做到这一点,就需要在 iife 的构建产物中包含所有的 es6 语法的 polyfill。下面开始准备因为需要用到三种模块的构建,所以为了项目结构清晰,需要将不同模块的构建配置文件分开。创建一个 config 文件夹,并且在里面创建三个 rollup 配置文件由于不同配置文件的插件配置是高度重合的,所以单独列出一个getPlugins.js文件处理插件,减少代码的重复性getPlugin.js// getPlugins.js import commonjs from "@rollup/plugin-commonjs"; import image from "@rollup/plugin-image"; import resolve from "@rollup/plugin-node-resolve"; import nodeExternals from "rollup-plugin-node-externals"; import postcss from "rollup-plugin-postcss"; const basePlugins = [resolve(), commonjs(), postcss({ extract: "rollup-build.css" }), image()]; 首先准备一个基础的 basePlugins,里面有各个模块都需要的基础功能,resolve() , 解析第三方依赖commonjs(), 解析 commonjs 模块postcss({ extract: "rollup-build.css" }),解析各种 css 文件格式,其中的参数表示将组件库的 css 样式都提取出来放到一个rollup-build.css文件中image(),解析各种图片格式,将图片转换为 base64 格式准备 esm 的插件// getPlugins.js import esbuild from "rollup-plugin-esbuild"; import nodeExternals from "rollup-plugin-node-externals"; export const esmPlugins = [...basePlugins, nodeExternals(), esbuild()]; 构建 esm 模块,编译插件需要处理 ts 和 react 代码,上篇文章中是用rollup-plugin-typescript处理 ts 代码,用rollup-plugin-babel处理 react 代码,输出的最后结果是 es6 代码。这份工作完全可以交给 esbuild 来做,esbuild 可以同时处理 ts 和 react 代码,而且速度还一个数量级在代码编译, esbuild 相较于 webpack,babel 会快很多nodeExternals 是用来排除所有的所有的第三方依赖的,这样组件库的构建产物体积就会足够的小准备 umd 模块// getPlugins.js export const umdPlugins = [ ...basePlugins, nodeExternals(), esbuild({ tsconfigRaw: { compilerOptions: { jsx: "react", }, }, }), ];umd 模块相比于 esm 模块,有个不同的地方--esbuild 的参数。这个参数的作用是使构建之后的 react 组件生成 reactElement 函数是 React.createElement,而不是 jsx/runtime中的函数。这是 umd 构建产物 -- Input 组件 的截图这样做的目的是用 script 引入的时候,可以少引入一个jsx/runtime的包使用了这种设置,是不是需要在组件中显示引入 React变量呢?答案是:不需要准备 iife 模块// getPlugins.js import { babel } from "@rollup/plugin-babel"; import { DEFAULT_EXTENSIONS } from "@babel/core"; export const iifePlugins = [ ...basePlugins, esbuild({ tsconfigRaw: { compilerOptions: { jsx: "react", }, }, }), // 处理低版本浏览器的polyfill babel({ presets: [ [ "@babel/preset-env", { targets: "> 0.25%, not dead, IE 10", }, ], ], exclude: /node_modules/, extensions: [...DEFAULT_EXTENSIONS, ".ts", ".tsx"], babelHelpers: "inline", //将所有的polyfill代码打包进bundle中 }), ];准备 iife 模块时,不需要将所有的第三方依赖都 external 掉,需要 external 的依赖会在 rollup.external 配置中单独列出来,这也是为了减少 script 引入产物的考量。所以这里拿掉了nodeExternals()插件因为 esbuild 并不能很好支持 es5 代码,所以,还单独加了一个 babel 插件,目的是将 es6 代码转译成 es5。其中的一些配置需要我们注意一个 targets,表示我们需要支持的浏览器数量,还有一个是 extensions,用来告诉 bable 插件,你需要它处理哪些文件。它默认是没有 ts、tsx 后缀的,所以我们额外添加。(这是坑,需要特别注意)babelHelpers 设置成 inline, 目的将 polyfill 代码都打包进构建产物中,而不是向 runtime 一样引入其中。虽然会导致构建产物增加,不过这是没有办法的事情其实要实现这个目的,babelHelpers: bundle其实是个更好的选择,但我用了这个值,构建就会报错,这是为什么:他们的区别在于 inline 会在构建产物每个文件都放一份 polyfill,而 bundle 对构建产物的所有文件都只有一个 polyfill。所以inline 模式会比 bundle 的构建产物体积更大。不过,其实对我也没有影响,因为我构建产物只有一个文件呀😄到此,getPlugins.js文件也就准备好了:// getPlugins.js import { DEFAULT_EXTENSIONS } from "@babel/core"; import { babel } from "@rollup/plugin-babel"; import commonjs from "@rollup/plugin-commonjs"; import image from "@rollup/plugin-image"; import resolve from "@rollup/plugin-node-resolve"; import esbuild from "rollup-plugin-esbuild"; import nodeExternals from "rollup-plugin-node-externals"; import postcss from "rollup-plugin-postcss"; const basePlugins = [resolve(), commonjs(), postcss({ extract: "rollup-build.css" }), image()]; export const esmPlugins = [...basePlugins, nodeExternals(), esbuild()]; export const umdPlugins = [ ...basePlugins, nodeExternals(), esbuild({ tsconfigRaw: { compilerOptions: { jsx: "react", }, }, }) ]; // script的依赖过多是不友好的 export const iifePlugins = [ ...basePlugins, esbuild({ tsconfigRaw: { compilerOptions: { jsx: "react", }, }, }), // 处理低版本浏览器的polyfill babel({ presets: [ [ "@babel/preset-env", { targets: "> 0.25%, not dead, IE 10", }, ], ], exclude: /node_modules/, extensions: [...DEFAULT_EXTENSIONS, ".ts", ".tsx"], babelHelpers: "inline", //将所有的polyfill代码打包进bundle中 }), ]; rollup.config.es.mjs这是 esm 模块的配置文件,内容很简单:// rollup.config.es.mjs import { esmPlugins } from "./getPlugins.js"; /**@type {import('rollup').RollupOptions} */ export default { input: "./src/index.tsx", output: { dir: "./dist/es", format: "esm", sourcemap: true, preserveModules: true, }, plugins: esmPlugins, }; 入口时 src 中的 index.tsx, 输出目录是dist文件夹下面的es文件夹。格式是 esm,生成 sourcemap,preserveModules: true的意思是编译不打包,构建产物仍然是按照开发的目录结构rollup.config.umd.mjs这是 umd 模块的配置文件:// rollup.config.umd.mjs import { umdPlugins } from "./getPlugins.js"; /**@type {import('rollup').RollupOptions} */ export default { input: "./src/index.tsx", output: { file: "./dist/umd/rollup-build.js", format: "umd", name: "RB", sourcemap: true, globals: { react: "React", "react-dom": "ReactDOM", }, }, plugins: umdPlugins, }; 入口和 esm 模块一样,出口是 dist 文件夹下面的 umd 文件夹。umd 还需要给出 script 场景下的全局变量名RB(取的是 rollup-build 首字母)其中 globals 的配置目的是告诉 rollup,组件库中引入的 react,react-dom,在 script 场景中,它们的全局变量名是什么。这个变量名不能是自定义的,要看具体的 react umd 格式文件中是什么那 react 举个例子:先找到 ract 中 umd 格式的文件红圈圈出来的位置,就是浏览器环境下的定义,给 global 上赋值了一个 React 属性,所以 react 库在 script 环境下的全局变量名称,就是 React红圈上面两行,分别是 commonjs 环境,和 AMD 环境,这就是为什么 umd 可以支持三种环境的原因所在了每 external 一个库,就要在 globals 中专门列出来一个,万一依赖库有十多个,那就太麻烦了。有没有一个库是专门维护这样一个映射关系的?rollup.config.iife.mjs这是 iife 模块的配置文件:// rollup.config.iife.mjs import { iifePlugins } from "./getPlugins.js"; /**@type {import('rollup').RollupOptions} */ export default { input: "./src/index.tsx", output: { file: "./dist/iife/rollup-build.js", format: "iife", name: "RB", sourcemap: true, globals: { react: "React", "react-dom": "ReactDOM", }, }, plugins: iifePlugins, external: ["react", "react-dom"], }; 相同的地方就不讲了,重点关注和其他模块配置不同的地方format 要改成 iife输出路径,是在dist/iife目录下面要额外地写出要 external 哪些库。原因之前提到过,减少 script 场景下需要额外引入的依赖,所以只将消费端大概率也会 external 的库,external 出去到此,所有模块的配置文件都准备好了,下面准备 package.jsonpackage.json{ "main": "./dist/umd/rollup-build.js", "types": "./dist/types", "module": "./dist/es/index.js", }这个配置是面向消费端的,配置了不同模块的入口。如果 commonjs 模块引入,node 就会返回 umd 下面的文件,如果是 esmodule 模块引入,node 就会返回 es 下面的文件。下面来添加构建的 npm 脚本{ "scripts": { "prebuild": "rimraf dist && tsc", "build": "npm run build:es & npm run build:umd & npm run build:iife", "build:es": "rollup -c ./config/rollup.config.es.mjs", "build:umd": "rollup -c ./config/rollup.config.umd.mjs", "build:iife": "rollup -c ./config/rollup.config.iife.mjs", }, }当执行npm run build,就会同时执行三种模块的构建,&与&&不相同,&&是串行执行,用来连接两个命令,如果前面的命令执行失败,就会阻塞后面的命令。&是并行执行,也是连接两个命令,但前后命令不会相互影响不同模块的构建并没有前后关系,所以这里用并行执行其中,还有个 prebuild 的命令,其会在npm run build之前执行。prebuild 内容中,首先是删除 dist 目录,然后执行 tsc,用来生成 ts 的类型文件,还兼有类型检查的功能。如果 ts 类型报错,就会停止构建功能。当然,报错停止构建后,类型文件也没必要输出了,可以在 tsconfig 中加上"noEmitOnError": true,就可以优化的实现这一点了。构建脚本也准备好了,下面来执行下看看吧!两个细节:可以看到 log 是交替出现了,印证了构建过程是并行执行的iife 模块构建的时间是最长的,因为用到了 babel 对 es 代码降级对比下 umd 和 iife 构建后的组件代码:可以看到 iife 中函数被转换为了 function 形式,不是箭头函数配置文件的再优化rollup 支持导出数组类型的配置文件,也就是说可以同时对不同入口,不同模块进行构建可以这么做:在 config 文件夹下面创建一个 rollup.config.js 文件://rollup.config.js import rollupConfigIife from "./rollup.config.iife.mjs"; import rollupConfigUmd from "./rollup.config.umd.mjs"; import rollupConfigEs from "./rollup.config.es.mjs"; export default [rollupConfigEs, rollupConfigUmd, rollupConfigIife];文件中将不同模块的配置文件放在一数组中重新导出package.json 中可以修改 npm run build的脚本内容:{ "scripts": { "build": "rollup -c ./config/rollup-config.js", }, }其他的构建脚本可以不删除,类似与npm run build:es,npm run build:umd,如果有特别需求,可以单独对某个模块进行构建来执行一下:可以看到, umd 构建时间显著小于 esm,也许是重用了 esm 模块的构建中间产物吧🤔总结这篇文章分享如何对 rollup 构建的组件库进行优化,优化主要两个方向,一个构建速度,构建速度用 esbuild 替代 bable;还有一个是不同模块的构建产物,构建产物分成了三种,分别是 esm, umd, iife。不同模块有其不同的特点,用来适应不同的使用场景
0
0
0
浏览量531
青椒肉丝加点糖

rollup实战(二)之用vite搭建rollup组件库的开发环境

前言上篇文章分享了如何使用 rollup 搭建组件库,并且使用 npm link 来测试 rollup 的构建产物。最后文章遗留了一个问题,即组件库的开发环境不是很友好,测试组件还需要消费端的支持上篇文章传送:纯干货不废话,用rollup搭建组件库,再用vite搭建测试环境这篇文章来分享在组件库中,搭建一个开发环境,无需构建过程,就可以对开发的组件进行测试,并且组件的更改马上可以在浏览器中看到开发环境,我体验的最好的就是 vite 了,开箱即用,而且能实现项目的秒开,是前端项目开发的不二首选回顾回顾一下上篇文章搭建好的组件库:一共两个组件,Button 和 Input使用 rollup 构建,构建产物是 esm 格式,输出目录在 dist 中构建产物也没有打包处理,而是按照原来的文件结构输出。同时生成了对应的类型文件,放在了 types 文件夹中。这是对应代码仓库:rollup-build (github.com)搭建开发环境因为需要用到 vite,和 react,所以需要安装 vite 和 解析 react 代码的插件@vitejs/plugin-reactnpm i vite @vitejs/plugin-react然后在组件库目录中新建一个 dev 目录mkdir dev配置 vite在 dev 目录下创建一个 vite 配置文件 vite.config.jsconst { default: viteReact } = require("@vitejs/plugin-react"); const path = require("path"); /**@type {import('vite').UserConfig} */ module.exports = { Plugin: [viteReact()], server: { open: true, port: 8088, }, resolve: { alias: { "rollup-build": path.resolve(__dirname, "../src"), }, }, };配置中,使用了@vitejs/plugin-react插件来解析 react 语法。设置开发服务器端口号为 8088,并且在启动 server 之后,自动打开浏览器还设置了 alias,将rollup-build指向组件库的目录。这个很有用,为的就是在开发环境中,有真实的组件库调用体验没有 alias 之前,是这样调用的:import {Button} from '../src/Button';有了 alias 后,是这样调用的:import {Button} from 'rollup-build/Button'配置 typescript配置了 alias 后,vite 是认识了,但是 ts 并不认识,会报错:所以需要给 typescript 加上 paths 的配置,{ "compilerOptions":{ "paths": { "rollup-build/*": [ "./src/*" ] }, } }为了方便理解,paths 配置需要加在组件库中的 tsconfig.json 文件中然后再在 dev 目录下面新建一个 tsconfig.json。建好后,整个组件库就有两个 ts 配置文件了:里面一个,外面一个里面的配置文件的内容如下:{ "extends": "../tsconfig.json", "compilerOptions": { "jsx": "react-jsx" }, "include": [ "src" ] }为什么需要两个 tsconfig.json。这个说来话长了。如果只用外面的配置文件会出现什么情况?现在外面配置文件的主要内容如下:{ "compilerOptions": { "rootDir": "./src", "baseUrl": "./", "jsx": "react-jsx", "declaration": true, "emitDeclarationOnly": true, "isolatedModules": true, "outDir": "./dist/types", "lib": [ "es2020", "DOM" ], "paths": { "rollup-build/*": [ "./src/*" ] }, }, "include": [ "./src/**/*" ] }由于其中的 include 是 src 文件夹:导致 dev 中的 TS 识别出错,如果在 include 中添加 dev 文件夹的路径:tsconfig.json 配置文件又会报错主要的意思是 rootDir 应该包含所有的源文件,但是现在的rootDir为./src,与 include 范围不相同,所以报错。那好,那就修改下 rootDIr,使其范围不仅有 src 文件夹,还有 dev 文件夹:这时候 build 一下,看看会发生什么:可以看到,构建产物中的 types 文件夹下面多了一个 dev 文件夹,这是我们不想看到的。dev 只是用于开发测试,是不应该放进来的。所以只用外面的 ts 配置文件是不妥的,得两个一起用!分析内部的 ts 配置文件现在回过头来看看 ts 内部的配置文件{ "extends": "../tsconfig.json", "compilerOptions": { "jsx": "react-jsx" }, "include": [ "src" ] }首先使用 extends 继承外面的配置文件,然后include src 文件夹,表示在当前文件夹下只需要分析 src 文件中内容即可"jsx": "react-jsx"为 react 开发服务的,有了这个配置后,tsx 中不单独引入 react 就不会报错了。ts 应该给个默认值为react-jsx,不然每次都要加这个东西。看看人家 babel 都支持这功能多少年了到这里,dev 环境的配置就做好了,下面开始正式编写代码引入组件,做测试在 src 文件夹下,新建 index.tsx, App.tsx// index.tsx import * as ReactDOM from 'react-dom/client' import App from './App'; ReactDOM.createRoot(document.getElementById('root')!).render(<App />)//App.tsx import Button from "rollup-build/Button" import Input from "rollup-build/Input"; const App = () => { return <div> <Button contents='' /> <Input /> </div> } export default App;在 App.tsx 中引入了两个组件,一个是 Button,一个是 Input,路径是上面配置的 alias,指向组件库的 src 文件夹代码写好了,下面就看看是否执行 OK启动开发环境项目添加一个 npm script:{ "scripts":{ "dev": "cd ./dev && vite" } }在 dev 目录中并没有创建一个 package.json,而是在组件库的 package.json 中添加 npm script执行 npm run dev之后,就会进入 dev 文件夹之后,再去执行 vite 命令项目成功运行修改下 App.tsx 的代码:保存,浏览器自动刷新:页面上也多了 i am app热部署和自动刷新也没有问题。搞定!!这是dev目录的代码:add-dev (github.com)总结:这篇文章分享了如何为组件库项目添加开发环境。使用的 vite 工具,能够实现低配置,秒开项目的极佳体验,大赞。有了开发环境之后,就不需要等到组件库构建之后才可以测试了
0
0
0
浏览量558
青椒肉丝加点糖

rollup实战(五)之用monorepo搭建组件库开发环境

前言应粉丝的建议,加更一篇使用 monorepo 搭建组件库的 playground,也就是本地的组件库测试环境之前也有一篇专门讲搭建组件库测试环境的:rollup实战(二)之用vite搭建rollup组件库的开发环境不过用 monorepo 似乎逼格更高点哈哈,所以这篇文章来分享下准备 monorepo首先准备一个空文件夹,终端执行npm init -y:是的,这是基于 npm 使用 monorepo然后创建 components 文件夹存放组件库代码进到 components 文件夹,用 npm 初始化一下npm init -y, 生成了一个 package.json:{ "name": "components", "version": "1.0.0", }我们可以把 components 当成一个变量空间,在根目录 package.json 中添加 workspace 属性:{ "name": "monorepo-demo-2", "workspaces": [ "components" ], } 没错,npm 就是通过workspace属性来管理同一文件夹下的不同项目的。每加一个项目,都需要往 workspace 中添加一个路径,表示向 npm 注册一个项目。每个项目中含有一个 package.json, npm 就是靠 json 中的 name 属性来识别不同项目上面我们完成了在一个 monorepo 中,创建并注册一个项目,主要有三步:创建文件夹 components在 components 下执行 npm 初始化在根目录中的 packagejson 注册 components这三步可以简化成一个命令npm init -w components -y。如果 components 文件夹已经存在,并且已经 npm 初始化,那么这个命令就只会执行第三步你可以将所有项目放在一个叫 packages 文件夹下面,然后在workspace 添加一个 package/*, 表示 packages 文件夹下面有多个项目,npm 靠不同项目的 package.json 中的 name 属性来识别不同项目安装依赖接下来就可以向 components 组件库安装依赖了, 在根目录执行:npm i rollup -w components这个命令的意思是向 components 项目安装一个 rollup 依赖,-w指定项目。执行完安装命令之后,就是这样:在项目根目录中生成了一个 node_modules 文件夹,里面有刚才安装的 rollup 依赖。这就是 monorepo 于普通项目的不同之处了--多个项目共享一个 node_modules,并不会在项目目录里面生成 node_modules。而且 node_modules 中还有一个 components 文件夹的软连接,也就是说 components 本身也被提升到 node_modules 中了,这是多个项目之间互相共享代码的关键。node 环境中查找依赖的顺序是,先在当前文件夹的 node_modules 查找依赖,如果没有,就往父级目录的 node_modules 中查找。逐级往上,直到查询到为止,或者查询到根目录为止然后接着安装 rollup 构建需要的其他依赖:npm i @rollup/plugin-commonjs @rollup/plugin-node-resolve -w components npm i rollup-plugin-node-external rollup-plugin-postcss -w components npm i typescript @rollup/plugin-typescript tslib -w components npm i @babel/core @babel/preset-env @babel/preset-react @rollup/plugin-babel -w components npm i react react-dom @types/react @types/react-dom -w components不得不说,rollup 组件库的依赖是真滴多编写组件库为了方便掩饰,只写一个简单的组件和构建配置文件:组件很简单,只有一个 Button,还有依赖于 Button 的 Search 组件:这是 Button 组件的内容:这是 Search 组件的内容:index.ts 作为整个组件库的入口和出口,内容是这样的:import resolve from "@rollup/plugin-node-resolve"; import commonjs from "@rollup/plugin-commonjs"; import { babel } from "@rollup/plugin-babel"; import { DEFAULT_EXTENSIONS } from "@babel/core"; import typescript from "@rollup/plugin-typescript"; import nodeExternals from "rollup-plugin-node-externals"; /** @type {import('rollup').RollupOptions} */ export default { input: "./src/index.ts", output: { dir: "./dist", format: "esm", sourcemap: true, preserveModules: true, }, plugins: [ resolve(), commonjs(), typescript(), babel({ presets: [ "@babel/preset-react", [ "@babel/preset-env", { targets: ">0.2%, not dead, not op_mini all", }, ], ], exclude: /node_modules/, extensions: [...DEFAULT_EXTENSIONS, ".ts", ".tsx"], babelHelpers: "bundled", }), nodeExternals({ devDeps: true }), ], };配置项的意思就不介绍了,感兴趣可以查看我专栏的其他文章:rollup构建组件库系列试一下构建功能是否 ok。添加一个 npm script:{ "name": "components", "version": "1.0.0", "scripts": { "build": "rollup -c rollup.config.js" }, }添加了一个 build script,在 components 目录中执行npm run build后,目录中多了一个 dist 文件夹:内容没问题也可以在 monorepo 根目录中执行构建命令:npm run build -w components。这个命令的意思是执行 components 项目的 npm run build 命令如果根目录中有多个项目需要执行 npm run build 命令,可以在根目录执行npm run build -w ./表示执行当前目录下所有项目的npm run build命令准备 playground上面准备好了 rollup 组件库,还需要一个本地的开发环境 playground。为了方便,直接用 vite 脚手架搭建的 react-ts 模版。在项目根目录中执行 npm create vite playground -- --template react-ts。执行完后,就可以在可以根目录中看到生成了一个新文件夹:然后将 playground 注册到根目录的 monorepo 中,在根目录中执行npm init -y -w playground。执行完后,就可以在根目录的 package.json 中看到:基本环境准备好了,接下来就可以在 playground 中引用组件库中的组件了。不过还有件事:在 components 目录下的 packagejson 中注册组件库的入口:{ "name": "components", "version": "1.0.0", "description": "", // 注册入口 "module": "./src/index.js", }然后在 playground 中安装 components:npm i components -w playgroundplayground/package.json:{ "name": "playground", "private": true, "version": "0.0.0", "dependencies": { // 添加依赖项 "components": "^1.0.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, }上面的依赖项可以换成"components": "*"下面就可以在 playground/src/App.tsx 中引用组件库组件了:import { Button } from "components"; import "./App.css"; function App() { return ( <> <Button.Search /> <Button content='button from playground' /> </> ); } export default App;引用了 Button,以及 Search。启动项目看看效果吧。在根目录中执行npm run dev -w playground表示执行 playground 项目下面的npm run dev命令启动成功,打开网址看看:刚好是两个 button,没有问题为什么Button可以访问components呢?因为修改下代码:function App() { return ( <> <Button.Search /> <Button content='button from playground 1' /> <Button content='button from playground 2' /> </> ); }保存刷新浏览器:没有问题!playground 就搭建好了这是项目代码:zenos / monorepo-demo 刚兴趣的宝子们可以去瞅瞅总结这篇文章分享了如何使用 monorepo 来搭建组件库的 playground,本文的 monorepo 也是基于 npm 来使用的。除了 npm,也可以使用 pnpm,yarn 来搭建 monorepo,都是没有问题的。虽然本文的组件库是基于 rollup,但不限于 rollup,其他的工具也是可以的。归根结底,monorepo 就是借用了 node_modules依赖查询路径这一规律,让不同项目的代码和依赖得以共享
0
0
0
浏览量1030
青椒肉丝加点糖

Rollup实战:构建高效组件库与开发环境

这个专栏将带你深入学习如何使用Rollup构建高效的前端组件库,并搭建相应的开发环境。从基础搭建到优化和测试,每篇文章都涵盖了不同方面的实战内容。你将学习如何使用Rollup和Vite搭建组件库的开发环境,从开源的角度优化组件库,测试不同模块的构建产物,并了解如何使用monorepo来搭建组件库开发环境。通过这个专栏,你将掌握使用Rollup构建高效组件库所需的核心知识和实践技巧。
0
0
0
浏览量1312
青椒肉丝加点糖

JavaScript基础(三)函数、作用域

一、函数        函数是一个功能体,提供若干个数据,返回处理结果用于封装重复执行的代码。有系统函数和自定义函数之分。1. 系统函数转数值 Number ( );转整型 praseInt ( );转浮点型 parseFloat ( );警示框 alert ( );输入款 prompt ( );isNaN :检测一个值是否为NaN,用于检测用户输入的值是否为数值型。执行过程中,会隐式将数据转换为数值型,是NaN(不是数字)则返回true,否则返回false。isFinite:检测一个值是否为有限值,只有无穷(infinity)是无限值。是有限值返回true,不是有限值返回false。eval ( ) :执行字符串中的表达式。 2. 自定义函数的创建(1)创建普通函数//格式: function 函数名称 ( ) { 函数体 } //调用方式: 函数名();         PS:函数体就是封装的重复执行的代码;创建函数以后,函数体的代码不会执行,函数每调用一次,代码才会执行一次。(2)创建带有参数的函数//格式: function 函数名称 (参数列表) { //此处参数用于接收外部传递的数据(形参) 函数体 } //调用方式: 函数名称 (参数列表); //此处参数为实际传递的数据(实参)        PS: 实参会赋值给形参,实参的数量和形参的数量可以不同,如果形参未被赋值则为undefined。(3)创建带有返回值的函数//格式: function 函数名称 (参数列表) { 函数体 return 值; } //调用方式: 函数名称 (参数列表);         PS:return后的值为返回值,该值是什么,调用函数后的结果就是什么,如果函数中没有return或者return后不加任何值,则返回结果为undefined,return执行后,就会结束函数的执行而且它能直接放到一个表达式的内部。 return 与 break 的区别:return 用于函数中,结束函数的执行。break 用于循环或者 switch-case,结束循环或者 switch-case 的执行。3. 递归        递归是指在函数内部调用自身这个函数,默认是一个死循环。在使用时需要有边界条件,要结合 return 使用。如下,通过一道例题来解释://用递归求斐波那契数列第n项的值 function fib(n){ //边界条件:当n为1或者n为2的时候返回1 if (n === 1 || n === 2){ return 1; } //第n项的值返回 第n-1项 + 第n-2项 的值 return fib(n-1) + fib(n-2); } console.log( fib(6) );//输出值为8PS:斐波那契数列,第一项和第二项为1,从第三项开始每项的值为前两项之和,如:1,1,2,3,5,8,13,21......首先创建带有参数 n 的函数 fib,n 代表数列的第 n 项,因为斐波那契数列的前两项为1,所以判断 n 为1或者 n 为2时返回1。除前两项之外,剩余的返回该项的前两项之和即(n-1)项和(n-2)项之和。直接调用 fib(n-1)+fib(n-2) 就是使用了递归的思想,调用函数本身。函数的递归需要注意一点:JavaScript 的运行特点是单线程,无法充分利用 CP U的内核,深层次的递归嵌套 JS 则会非常缓慢,所以递归并不是在任何情况下都适用。4. 匿名函数        匿名函数就是没有函数名称的函数 function ( ){ }(1)创建匿名函数var fn = function( ) { } 函数表达式方式(变量名称即函数名称) function fn( ) { } 函数声明方式对比匿名函数和函数名称( ):        函数名称  本质上就是一个变量,保存了一个函数        函数名称( );  调用一个函数,执行函数体中的代码,得到函数的返回值对比函数声明和函数表达式 :        函数声明存在函数的提升,可以先写调用再写创建        函数表达式只是提升变量的声明,不提升赋值,必须先写创建再调用(2)匿名函数的自调用(function(){ })();匿名函数自调用的目的是创建一个函数作用域,防止全局污染。全局污染:全局变量访问范围大,对其他变量带来的影响。举例:(function (){ var num = 2; console.log(num); })();函数体中变量num的值为2,进行自调用后打印 num。(3)回调函数       将函数以参数的形式传递,传递的这个函数就是回调函数。如下://回调函数 function tao(madai){ console.log('开始第1棒'); console.log('到达第1棒终点'); //madai = dong; //传递的函数被madai接收 //调用madai,意味着调用传递的参数 madai(); } function dong(){ console.log('开始第2棒'); console.log('到达第2棒终点'); } //此处dong作为参数进行传递,所以dong就是回调函数 tao(dong); tao(function(){ console.log('第三棒开始'); }); console.log(typeof tao);//function二、作用域        全局作用域:在函数以外的就是全局作用域,声明的变量为全局变量,在任意的作用域下都可以访问到全局变量。        函数作用域:在函数内的为函数作用域,声明的变量为局部变量,局部变量只能在当前的作用域下访问到。在函数作用域下又有全局函数与局部函数之分,在全局作用域下创建的函数就是全局函数,可以在任意作用域下访问;在局部作用域下创建的函数就是局部函数,只能在当前作用域下访问。       特别注意:在程序执行前,会将 var 声明的变量提升到变量所在作用域的最前面,但只提升声明,不提升赋值,这是变量提升;在程序执行前,会将整个函数提升到所在作用域的最前面,这是函数提升。函数提升优先于变量提升。如下程序://全局作用域 var a = '北京';//全局变量 function s(){ //函数作用域 var b = '海淀区';//局部变量 console.log(a); } shi(); console.log(b); function h(){ //函数作用域 var c = '石景山区';//局部变量 }        在函数以外的就是全局作用域,所以声明的变量 a 就是全局变量。函数 s 和 h 以内的为函数作用域,所以在它们内部声明的变量 b、c 全部为局部变量。a 为全局变量,即使在函数 s 的作用域下进行打印依然能够成功,因为它是全局变量。而 b 和 c 均为局部变量,只有才函数以内打印才能成功。
0
0
0
浏览量1017
青椒肉丝加点糖

CSS(二)元素基础样式、字体属性、文本属性

一、元素基础样式1. 尺寸和单位        宽度width和高度height使用长度单位:px、pt、rem、em、%等;        max-width 最大宽度,max-height 最大高度;        min-width 最小宽度,min-height 最小高度,不允许出现负值。        一般PC端网页使用 px 或者 pt,移动端使用 %、em、rem、vw、vh 等响应式单位。2. 颜色(1)英文颜色        常用 red、green、blue、yellow、orange、pink、purple、gold 等,还有透明色transparent。(2)十六进制颜色        格式为 #rrggbb,1、2 位代表红色范围;3、4 位代表绿色范围;5、6 位代表蓝色范围。值的范围为 0-9,a-f。如果三组都是相同的值,可简写,如:#00ff00 --> #0f0。(3)RGB颜色        格式为 rgb(r,g,b);  r 代表红色色值;g 代表绿色色值;b 代表蓝色色值。        取值范围为0~255 之间的256个数。        rgba();a代表透明度,取值 0~1 之间的数字,0 代表完全透明 rgb(255, 5, 251); rgba(15, 2, 15, 0.5);(4)web 安全色        安全色是用于网页的标准色彩,它比标准的 rgb 色彩要少,如果网页设计的时候用了非 web 安全色,那这个网页在不同的电脑显示出来可能是不同的颜色。3. 边框(1)边框属性(2)边框的方向(3)简写        border:边框宽度  边框样式  边框颜色(最常用) border:30px solid green; border-bottom:10px solid blueviolet;(4)案例:三角形的 CSS 写法.sjx { width: 0; height: 0; border: 50px solid transparent; border-bottom-color: black; }4. 元素的分类(1)元素的显示属性(2)元素特性5. 显示和隐藏属性二、字体属性1. 字体大小——font-size: 30px;   设置字号,        字体大小可以使用不同的单位,如 px、pt、em、rem、vw等等,不允许负值像素。几种常见取值如下:        Google浏览器字体大小默认为16px,最小12px。2. 字体系列——font-family: "华文新魏";   设置所需要的字体。        推荐字体系列:(可直接复制使用)<!--移动端项目:--> font-family:Tahoma,Arial,Roboto,"Droid Sans","Helvetica Neue","Droid Sans Fallback","HeitiSC",sans-self; <!--pc端(含Mac)项目:--> font-family:Tahoma,Arial,"Helvetica Neue","Hiragino Sans GB",Simsun,sans-self; <!--移动和pc端项目:--> font-family:Tahoma,Arial,Roboto,"Droid Sans","Helvetica Neue","Droid Sans Fallback","HeitiSC","Hiragino Sans GB",Simsun,sans-self;3. 字体字重(粗细)——font-weight: 400;   设置字体的粗细。        值为介于 1 和 1000 之间的数字类型值,必须要是 100 的倍数。常用关键词:normal(400 默认)、bold(粗体700)、lighter(细体300)。4. 字体样式——font-style: italic;   设置字体的样式。5. 简写        格式:font:字体样式 字重 字号 字体系列(不可改变顺序)font: italic 600 20px "仿宋";三、文本属性1. 字体颜色        color:颜色的色值;2. 文本对齐方式——text-align: center;        该属性针对块级元素中的内联元素,它需要写在父级(块级元素)中,不能写在子元素中。3. 文本的行高—— line-height: 70px;        行高=文字上下间距+文本高度;使单行文字在父元素垂直居中时使文本的行高等于父元素的高度即可。4. 文本线条修饰5. 首行缩进——text-indent: 2em;6. 文本换行        正常文字拥有默认的 white-space:normal 属性,当达到定义的宽度之后就会自动换行,而连续的英文字符和数字不能换行,在 div 中英文字母之间没有空格的话,它会默认为这是一个英文单词,所以一次性输出不换行7. 文本溢出.d9 { width: 300px; /* 限宽 */ white-space: nowrap; /* 强制不换行 */ overflow: hidden; /* 多余部分不显示 溢出部分隐藏 */ text-overflow: ellipsis; /* 文本溢出显示 */ }8. 文字阴影        格式:text-shadow:x 轴偏移量  y 轴偏移量  模糊半径的大小  颜色值text-shadow: 10px 10px 5px brown;9. 垂直对齐方式——vertical-align: middle;        垂直对齐针对的是该元素前后的内联元素或者文字,而不是本身。常用关键值:
0
0
0
浏览量847
青椒肉丝加点糖

Node.js(一)概述、全局对象/函数、node各模块使用介绍

一、Node.js概述1. 对比JS        JS运行在客户端,存在多种解释器,有代码兼容性问题;Node.js运行在服务器端,只有一种解释器,没有代码兼容性问题。两者有相同自定义对象和内置(ES)对象,不同的宿主对象。        JS用于开发浏览器端的交互效果;Node.js 用于服务器端的开发,例如:数据库访问,其他服务器的调用。其实就是,JS负责前端,Node.js负责后台。2. 下载安装        安装node只需在官网直接下载安装即可。官网:Node.js 中文版:Node.js 中文网3. 运行 Node.js       运行方式有两种,打开命令提示行,脚本模式:node 文件;交互模式:node 回车(进入交互模式)        要知道 node 属于单线程的运行逻辑,支持数万个并发连接,适合做基于社交网络的大规模 web 应用,不适合做 CPU 密集型应用。二、全局对象1. global - 用于检测一个变量或者函数是否为全局        JS(浏览器)下的global对象名称为 window,在 Node.js 下,一个脚本文件不属于全局作用域。在JS下,一个脚本属于全局作用域,所以存在全局污染。var a = 1; //Node.js下: console.log( global.a );//undefined 不是全局作用域 //JS下: alert( window.a );//1 a为全局作用域2. console - 控制台对象,用于输出console.log(1); //输出日志 console.info(2); //输出消息 console.warn(3); //输出警告 console.error(4); //输出错误 console.time( m ); //开始计时 console.timeEnd( m ); //结束计时(开始计时与结束计时所提供的参数 m 要保持一致)浏览器输出效果如下:3. process - 进程,用于查看Node.进程        计算机上任何的软件运行都有相应的进程;process.arch         查看当前CPU架构process.platform  查看当前的操作系统process.version    查看Node.js的版本号process.pid          查看当前Node.js的进程编号process.kill( )        结束指定编号的进程4. Buffer - 缓冲区,常用于保存网络传输时的资源        缓冲区是内存中临时保存数据的区域;Buffer.alloc( 6,'abc涵' );  //创建Buffer,分配空间并存储数据,每个汉字占3个字节buf.toString( )                 //将Buffer转为字符串三、全局函数 - 定时器函数一次性定时器开启:var timer = setTimeout(回调函数,间隔时间) //间隔时间到,调用一次回调函数 清除:clearTimeout(timer);//一次性定时器 var timer = setTimeout(function(){ console.log('boom!!!'); //执行三秒后输出“boom!!!” },3000); //清除 clearTimeout(timer);周期性定时器开启:let timer = setInterval(回调函数,间隔时间) //每隔一段时间,调用一次回调函数 清除:clearInterval(timer);//周期性定时器 var timer = setInterval(function(){ console.log('滴滴'); //每两秒打印一次“滴滴” },2000); console.log(1); //清除 clearInterval(timer);立即执行定时器会将回调函数放入到事件队列,当主程序完成后会立即执行;nextTick早于setImmediate. 开启:let timer = setImmediate(回调函数) 清除:clearImmediate(timer) 开启:process.nextTick(回调函数) nextTick不能清除 定时器的回调函数是在程序最后执行的。四、模块的分类1. 自定义模块        在Node.js下每一个文件代表一个模块,每个模块是一个独立的功能体。举例:(模拟  主模块main.js;功能模块circle.js)//1.在功能模块中编写功能函数 function length(r){ return 2 * Math.PI * r;//周长 } function area(r){ return Math.PI * Math.pow(r,2);//面积 } //2.在功能模块中将要导出的内容放入默认的空对象 module.exports = { a:length, //将函数lengeh导出,导出的名字为a b:area //将函数area导出,导出的名字为b }; //3.在主模块中使用require函数将功能模块引入主模块 let obj = require('./circle.js'); console.log(obj.a(7).toFixed(2)); console.log(obj.b(8).toFixed(2)); 2. 第三方模块(包和NPM)        包是指目录模块,通常表示第三方模块;下载网址:npm;NPM 则是被用于管理包的工具,在Node.js安装的时候会附带安装。        切换命令行路径:  npm的使用:npm可以下载安装、卸载、升级、上传第三方模块3. 核心模块(1)querystring 模块        查询字符串:浏览器端向服务器端查询数据的一种方式,位于浏览器的地址栏,querystring 模块用于处理网址中查询字符串的工具模块;使用前需要先导入 querystring 模块:const querystring = require('querystring');//引入querystring模块 const querystring = require('querystring'); //console.log(querystring); //查询字符串 let str = 'kw=笔记本&price=4000'; //获取传递的数据 //解析为对象 let obj = querystring.parse(str); console.log(obj.kw); console.log(obj.price);(2)URL        统一资源定位,互联网上的任何资源(html、css、图形、数据......)都有对应的URL。eg:http://www.codeboy.com:9999/products.html?kw=戴尔let obj = new URL('https:/www.tmooc.cn:443/course/web.html?did=2106&cname=node.js'); let obj1 = obj.search.slice(1); let obj2 = querystring.parse(obj1); console.log(` 编号:${obj2.did} 名称:${obj2.cname} `);(3)fs模块        文件系统模块:用于文件操作,分为文件形式和目录形式;使用前需要先导入fs模块:const fs = require('fs');//引入fs模块 const fs = require('fs'); //查看文件状态 let s = fs.statSync('./04'); console.log(s); //创建目录 fs.mkdirSync('./mydir'); //删除目录 fs.rmdirSync('./mydir');4. 三种模块的引用方式
0
0
0
浏览量743
青椒肉丝加点糖

CSS(三)元素的修饰、背景设置

一、元素的修饰1. 圆角——border-radius        CSS中,任何元素都有四个角:        圆角的取值:        1个值:四个角相同        2个值:左上右下、左下右上        3个值:左上、右上左下、右下            4个值:左上、右上、右下、左下(顺时针)border-radius: 10px; border-radius: 10px 20px; border-radius: 9px 5px 3px; border-radius: 3px 10px 20px 30px;2. 盒子阴影——box-shadow        格式:box-shadow: x轴偏移 y轴偏移 羽化 扩展 颜色 内外阴影(可选,默认向外)第一、二个值: x 轴上的偏移量和y轴上的偏移量(正负值)第三个值:模糊半径的大小(羽化)不允许负值第四个值:扩展半径的大小,向四周扩散相等的大小,正值放大,负值缩小第五个值:颜色值第六个值:阴影向内 inset:默认阴影向外扩散box-shadow: 3px 5px 5px 1px green inset;3. 光标的设置4. 元素特有样式(1)表单轮廓 outline        格式:outline:width style color; 该属性常用与清空轮廓线。outline: none; outline: 0;(2)列表样式 list-style二、背景1. 背景颜色  background-color: 颜色色值;2. 背景图片  background-image: url(路径);        路径可以是绝对路径或者相对路径,注意外部 css 的路径,背景图必须要求元素具有宽度和高度。背景图和img的区别:img具有尺寸,不设置宽度高度,可以直接显示背景图必须设置宽度和高度img图片不可直接写文字,除非在img盒子外部定位背景图是可以在图片上写文字,背景图其实和颜色一样img一般用于产品展示,可以根据素材更新背景图一般左大背景或者更新小图标3. 背景图平铺        如果宽高大于图片大小,图片会重复显示;如果宽高小于图片大小,图片会显示不全。4. 背景图定位  background-position        背景图定位取值可以是关键词,也可以为正值和负值,正值向右移动负值向左移动。5. 背景图尺寸  background-size        在拉伸方向中有宽度拉伸和高度拉伸两种,所以可以指定两个值background-size:x轴拉伸 y轴拉伸;        注意在设置大图背景时最好限制最低宽度,这样低于预定宽度时就会出现横向拖拽条保证图片和内容显示完整。6. 简写        格式:background:color image repeat position;  四组值用空格分开,没有顺序;举例:.uname { background-image: url(./img/yhm.png); background-repeat: no-repeat; background-position: right; background-size: auto; background-size: auto 100%; }简写后:.uname { background: url(./img/yhm.png) no-repeat right/auto 100%;
0
0
0
浏览量306
青椒肉丝加点糖

JavaScript基础(二)选择语句、循环语句

一、流程控制(选择执行)1. if语句if ( 条件表达式 ) { 语句块 }它的格式很简单,常用来进行判断。先判断 if 之后的条件是否满足,如果满足则执行语句块。比如判断一个人的年龄,是否为成年人,代码如下:var age = 30; if (age >= 18){ console.log('成年人');//"成年人" }定义了年龄为30,使用if进行判断,30大于18,所以打印“成年人”。需要注意的是,如果 if 后的语句块中只有一行代码,则 { } 可以省略。2. if-else语句if ( 条件表达式 ) { 语句块1 }else{ 语句块2 }if-else 语句与 if 语句的区别仅仅在于加了else 判断,先判断 if 后的条件是否满足,如果满足执行语句块1,不满足则执行 else 后的语句块2。再拿上面的成年人来进行判断:var age = 12; if (age >= 18){ console.log('成年人'); }else{ console.log('未成年人'); }定义年龄 age 为12,12不大于18,所以要执行else后的语句,即打印“未成年人”。3. if-else嵌套if ( 条件表达式1 ) { 语句块1 }else if { 条件表达式n ){ 语句块n }else { 语句块n+1( 前面全为false才执行此语句块 ) }if-else嵌套则是多个 if-else 语句的组合,可以对多个条件进行判断。举个打印成绩的例子:var f = 75; if (f > 100 || f < 0){ console.losg('非法的成绩!'); }else if (f >= 90){ console.log('优秀'); }else if (f >= 80){ console.log('良好'); }else if (f >= 70){ console.log('中等'); }else if (f >= 60){ console.log('及格'); }else{ console.log('不及格'); }定义分数为75分,则依次往下进行判断,直到符合条件执行该条件下的语句块。该题打印结果为“中等”。4. switch-case语句switch ( 表达式 ){ case 值1: 语句块1 break;(结束执行,跳出当前语句) case 值n: 语句块n break; default: 语句块n+1( 前面全为false才执行此语句块 ) }switch-case 语句的运行方式为:先判断 switch 后的表达式的值,看它的值满足哪一个 case 的值,如果满足则执行该 case 后的语句块,执行结束后直接跳出(break)语句,如果前面都不满足,则执行 default 之后的语句块。switch-case 语句也可用来判断成绩区间:var score = 90; if (score < 0 || score > 100){ console.log('成绩错误!!!'); } var end = parseInt(score /= 10); switch(end){ case 10: case 9: console.log('优秀'); break; case 8: console.log('良好'); break; case 7: console.log('中等'); break; case 6: console.log('及格'); break; default: console.log('不及格!'); } switch-case 使用过程中需要注意以下几点:        表达式在与case后面的值比较的时候,用的是全等于(===)即同时判断值和类型。        switch-case只能是全等于的比较,但结构更为清晰,执行效率更高二、循环语句(循环执行)1. while循环初始值 while ( 循环条件 ){ 循环体 增量 }while 循环的执行为先判断循环条件,循环条件为 true,进入循环,false 则跳出。举一个简单的小例子:var i = 1; while (i <= 10){ i++; console.log('123456'); }定义 i 的值为1,条件为 i<=10,如果 i 满足条件则进入循环,i 自增后打印“123456”,直到 i 的值大于10为止。该程序结果为打印10次“123456”。2. do-while循环初始值 do { 循环体 增量 } while ( 循环条件 ) ;do-while 可以认为与 while 相反,先进行循环,再判断循环条件,结果为 true 继续进入循环,结果为 false 则结束。var i = 1; do{ console.log(i); i++; }while (i <= 10);该程序结果为打印1到10,先进行打印,再判断条件,直到条件判断为 false 跳出循环。3. for循环for ( 初始值 ; 循环条件 ; 增量 ) { 循环体 }for 循环可能是在编程过程中使用最多的一个循环,它的执行方式为从初始值开始,判断循环条件,结果为 true 则执行循环体,最后执行增量,增量之后再执行循环条件。直至循环条件为 false时循环结束。for (var i = 1;i <= 10;i++){ console.log(i); }该例子同样为打印1到10。4. 循环嵌套        所谓循环嵌套就是在一个循环体内部又出现了其他的循环,任意两个循环之间都可以进行相互嵌套。嵌套后外层循环控制循环的行数;内层循环控制每一行拼接的数量。//外层循环 for (var i = 1;i <= 5;i++){ //内层循环 for (var j = 1,str = '';j <= i;j++){ str = str + '*'; } console.log(str); } 如上代码,两个 for 循环嵌套,外层循环控制该循环为5行,内层则控制打印的行内容为‘*’且*的数量不断自增,效果如下:三、选择与循环语句例题        了解了选择与循环语句后,我们通过几道例题来巩固一下://1.一张纸可以折无限次数,纸的厚度为0.03毫米,问:折多少次可以达到珠穆朗玛峰高度8848米? var h = 0.00003;//初始化纸的厚度为0.00003 var count = 0;//count用于记录次数 do { h *= 2;//h = h * 2 count++; } while (h <= 8848);//直到h的值大于8848,跳出循环 console.log(count);//打印次数//2.用while函数写出1~100之间所有偶数的和 var i = 1; var sum = 0;//sum用于记录最后的和 while (i <= 100){//判断条件i为1~100 if (i % 2 === 0){//与2取余结果为0的则为偶数 sum += i; } i++; } console.log(sum); *///3.打印九九乘法表 for (i = 9;i >= 1;i--){ //内层循环,控制每行列数 for (j = 9,str = '';j >= i;j--){ //列 + * + 行 + = + 乘积结果 str = str + j + '*' + i + '=' + (j*i) + ' '; //将第3,4行的第2列后加一个空格 if (i === 9 && j === 1){ str = str + ' '; } } console.log(str);//每一行拼接结束后即打印 }//4.打印2000~2100之间前10个闰年 for (var year = 2000,count = 0;year <= 2100;year++){ //count用于记录闰年的个数 if (year % 4 === 0 && year % 100 !== 0 || year % 400 ===0){ console.log(year); count++; } if (count === 10){ break; } } console.log(count);
0
0
0
浏览量899
青椒肉丝加点糖

JS 高级(二)闭包、封装

一、闭包全局变量和局部变量在使用的过程中都各有优点,但它们也都有着自己的不足之处。全局变量的好处是可以被重用,但是极易被污染(注意一般公司中禁止使用一切形式的全局变量),局部变量虽不会被污染,但它无法重用。为了解决此缺陷,要给一个函数定义一个专属的且可重用的变量,只有函数自己可用,其他函数不可用时,就用到了闭包!闭包是既重用变量,又保护变量不被污染的一种编程方法,外层函数调用后,外层函数的作用域对象,被内层函数引用着,无法释放,就形成了闭包对象。闭包的使用分为三步:(1)用外层函数包裹要保护的变量和使用变量的内层函数(2)在外层函数内部,返回内层函数对象。(3)调用外层函数,用变量接住返回的内层函数对象。<script> // 1.用外层函数包裹要保护的变量和内层函数 function mother() { var total = 1000; // 2.外层函数返回内层函数对象 return function (money) { total -= money; console.log(`用了${money}元,还剩${total}元`); } } // 3.调用外层函数,用变量接住返回的内层函数 var pay = mother(); pay(100);//剩900 // 此处total的值不会干扰mother函数中定义的值 total = 0; pay(100);//剩800 pay(100);//剩700 </script>然而,闭包也存在一定的不足,闭包返回的内存函数,比普通函数多占用一块内存空间(外层函数的函数作用域对象);所以,如果一个闭包不打算再使用了,就应该及时释放它。保存内层函数的变量=null,这样就释放了内层函数对象,同时也释放了外层函数的作用域对象。二、面向对象程序中将来会保存大量的数据。而大量数据如果零散的随意管理,极容易出错!而且用着不方便。所以在今后程序中,都是用面向对象的方式来管理大量数据的。程序中会将描述一个事物的多个属性和功能集中保存在一个对象结构中,再起一个名字。面向对象三大特点:封装、继承、多态。1. 封装封装是指创建一个对象,集中保存现实其中一个事物的属性和功能,极其便于大量数据的管理维护。封装有3种方式:(1){ },创建一个对象时常用,格式如下var 对象名={ 属性名: 属性值, ... : ... , 方法名: function(){ ... } }访问对象中的属性或方法时,用--对象.属性名--或--对象.方法名()--即可。但是直接用{ }进行封装时,在对象自己的方法内,想使用对象自己的另一个属性名时,会报错!说xxx属性名未定义,解决此问题可用两种方式:a:写死对象名.属性名,但是一旦对象名发生变化,而对象内写死的部分对象名,都会报错!故此方式不推荐。b:今后,对象中的方法中,只要想使用当前对象自己的属性或其他方法时,都用加this。this是每个函数内自带的,不用创建,直接使用专门指向正在调用当前函数。<script> var lilei = { sname: "Li Lei", sage: 11, intr: function () { // ----------此处的this指代.前面的对象---------- console.log(`I am ${this.sname},I am ${this.sage}岁`); } } console.log(lilei.sage); lilei.intr(); lilei.sage++; console.log(lilei.sage); lilei.intr(); </script>(2)new,格式如下var 对象名=new Object();提示:function == new Function()强行给空对象中添加新属性和新方法,-- 对象名.新属性=属性值; --、-- 对象名.新方法=function(){ ... this.属性名 ... } --。可以看出,js 中所有对象底层都是关联数组。在访问成员时,标准写法为-- 对象名/数组名["成员名"] --,简写为-- 对象名/数组名.成员名 --;如果成员名是数字时,只能用-- 对象名/数组名[数字] --, 如果成员名是变量时,只能用-- 对象名/数组名[变量] --,不要加引号。需要注意:强行给不存在的位置赋值,不但不会报错,而且还会自动添加该属性;强行访问不存在的位置的值,都不会报错,而是返回undefined。<script> var lilei = {}; lilei["sname"] = "lilei"; lilei.sage = 11; console.log(lilei); console.log(lilei.className); //undefined 强行访问不存在的位置的值,都不会报错,而是返回undefined for (var 属性名key in lilei) { console.log(`属性名:${属性名key},属性值:${属性名key}`); } var lilei = []; // js中所有对象底层都是关联数组 lilei.sname = "Lilei"; lilei["sage"] = 11; console.log(lilei); console.log(lilei["className"]); //undefined for (var 属性名key in lilei) { console.log(`属性名:${属性名key},属性值:${属性名key}`); } </script>举例: 克隆一个对象<script> var liang = { sname: "久胜战神", sage: 1000, sex: "男" } // 进行克隆 function clone(old) { // 1.先创建一个空对象等着 var now = {}; // 2.遍历元对象中的属性名 for (var oldlist in old) { // 3.获取原对象中原属性值,再添加同名属性 var oldvalue = old[oldlist]; now[oldlist] = oldvalue; } return now; } var liang2 = clone(liang); console.log(liang2); console.log(liang2 == liang); </script>(3)用构造函数用 { } 一次只能创建一个对象。如果想创建多个相同结构的对象时,代码就会很多重复,这样极其不便于将来的维护。当想反复创建多个相同结构,只是内容不同的对象时,都用构造函数。定义构造函数:function 类型名(形参1, 形参2, ...){ //将来要加入到新对象中的规定的属性 this.属性名=形参1; this. xxx = xxx; this.方法名=function(){ ... this.属性名 ... } }用构造函数反复创建多个相同结构的对象:var 对象名=new 类型名(实参值1, 实参值2, ...)举例:定义构造函数规定学生类型对象的统一结构<script> // 定义构造函数 // ---------此处this指代新对象--------- function Student(sname, sage) { this.sname = sname; this.sage = sage; this.intr = function () { console.log(`我叫${this.sname},我今年${this.sage}岁`); } } // 用构造函数反复创建多个相同结构但内容不同的对象 var lilei = new Student("李雷", 45); var hmm = new Student("韩梅梅", 30); console.log(lilei); lilei.intr(); console.log(hmm); hmm.intr(); </script>
0
0
0
浏览量724
青椒肉丝加点糖

MySQL(一)认识MySQL、常用管理命令、列类型列约束、查询语句

一、软件生命周期和计算机数据存储方式1. 软件生命周期        定义期:可行性研究阶段/需求分析阶段;        开发期:概要设计阶段/详细设计阶段/编码实现阶段/测试阶段;        维护期:部署阶段/维护阶段。2. 计算机对数据的存储,有4个方面通过特定的文件如excel、word等存储,只适用于存储小量数据且速度慢;内存,临时存储,运行时会有数据产生并存储,结束运行后数据即销毁;速度快;第三方云服务器,共享;数据库服务器。MySQL属于数据库服务器存储的范畴。二、数据库        数据库的作用就是按照一定的形式组织存放数据,目的是为便于操作数据,即增、删、改、查。数据库的发展历程为:网状数据库-->层次型数据库-->关系型数据库(RDBMS)-->非关系型数据库。1. 常见的关系型数据库SQLite——微型数据库,常用于移动端MySQL——开源RDBMS,是一种关联数据库管理系统,将数据库保存在不同的库中,每个库可包含多个表,表中可以有多行多列的数据,可用于各种操作系统SQL Server——Microsoft开发的中型数据库,只适用于Windows操作系统Oracle——Oracle开发的中大型数据库,可用于各种操作系统DB2——IBM开发的中大型数据库,常与IBM服务器搭配2. MySQL部署结构        MySQL部署分服务器端和客户端,服务器端负责存储维护数据,客户端负责连接服务器端,对数据进行增删改查操作。使用客户端连接服务器端时只需要执行命令:mysql.exe -h127.0.0.1 -P3306 -uroot -p -h,host IP地址/域名 eg:127.0.0.1/localhost(永远指向自己本身的电脑) -P,port 端口(此处为3306端口) -u,user 用户名(root是管理员账户,在root下密码为空) -p,password 密码此命令也可以简写为:mysql -uroot3. 常用管理命令(必须以英文“;”结尾)quit;  退出连接show databases;  显示当前所有数据库use 数据库名称;  进入指定的数据库show tables;  显示当前数据库下的所有数据表desc 数据表名称;  描述数据表中都有哪些列4. 常用SQL命令以及举例(1)定义数据结构(DDL)drop database if exists jd; //丢弃数据库jd(存在的基础上) create database jd; //创建数据库jd use jd; //进入数据库jd create table student ( id int, name varchar ( 8 ), sex varchar ( 1 ), score int ); //创建表student,包括id、name、sex、score四列 (2)操作数据(DML)insert into student values('1','张三','M','99'); //向student表中插入一行数据 delete from user where uid="2";  //删除uid为2的行数据 update user set upwd="666666",isOnline="n" WHERE uid="3"; //修改uid为3的行密码为666666,在线状态为n(3)查询数据(DQL)select * from student; //查询student表中的所有数据三、列类型        列类型指在创建数据表时,指定的列所能存储的数据类型。1. 数值型2. 日期时间型3. 字符串型    字符串型和日期时间型 必须加引号四、列约束        列约束的意思是MySQL对要插入的数据进行特定的验证,只有符合条件才允许插入(位于列类型之后)。1. 主键约束  primary key        声明了主键约束的列,不允许插入重复,一个表中只能有一个主键约束,通常用于编号列,可加快数据查找速度。        自增列 Auto_increment:自动增长,声明了自增列,插入数据时只需要赋值为 null,就会获取最大值然后加1插入。声明了自增列也允许手动赋值。2. 非空约束  not null        声明了非空约束的列上禁止插入Null。3. 唯一约束  unique        声明了唯一约束的列不允许插入重复的值,但是 unique 允许插入重复的 null 甚至多个 null,一个表中可以有多个唯一约束。4. 默认值约束  defaul        可以使用 default 关键字设置默认值,default使用时不加引号。5. 检查约束  check        也称自定义约束,用户可以制定约束的条件。但是 MySQL 不支持检查约束,认为会极大影响数据插入数据,后期需要通过 JS 实现。6. 外键约束  foreign        声明了外键约束的列称为外键列,这一列取值范围到另一个表的主键中,是为了让两个表建立关联。外键约束用法特殊,常用于创建表的最后一行,外键列要和对应的主键列的列类型保持一致。格式如下:格式:foreign key(外键列) references 另一个表(主键列) eg:foreign key(familyId) references family(fid)五、MySQL查询语句注:以下举例中 ,emp为员工表,dept为部门表1. 简单查询(1)查询特定的列     eg:查询所有员工的编号和姓名 select eid,ename from emp;(2)查询所有的列     eg:查询员工表emp中所有信息 select * from emp;(3)给列起别名       eg:查询所有员工的编号和姓名并起别名 select eid as 编号,ename as 姓名 from emp;(4)显示不同的记录eg:查询有哪些性别的员工 select distinct sex from emp;(5)查询时执行计算eg:查询所有员工姓名及年薪 select ename,salary*12 from emp;(6)查询结果排序     eg:查询所有部门数据,结果按照编号升序排列 select * from dept order by did asc;(7)条件查询             eg:查询编号为5的员工的数据 select * from emp where eid=5;(8)模糊条件查询     eg:查询姓名中含有“e”的员工 select * from emp where ename like "%e%"; % 表示匹配任意个字符, _ 表示匹配一个字符,以上两个匹配符须结合like关键字使用(9)分页查询        当查询的结果中数据太多,一次显示不完,就可以使用分页显示。分页查询需要两个已知条件:当前页码+每页数据量。语法:select * from emp limit 开始查询的值, 每页的数据量;eg:假设每页显示五条数据,分别查出前三页 第1页:select * from emp limit 0,5; 第2页:select * from emp limit 5,5; 第3页:select * from emp limit 10,5; 注意:开始查询的值=(当前的页码-1)* 每页数据量2. 复杂查询(1)聚合查询/分组查询eg:通过员工编号查询员工数量 select count(eid) from emp; eg:查询各部门员工 最高工资,员工数量,平均工资 select max(salary),count(*),avg(salary),deptId from emp group by deptId; eg:查询所有员工出生的年份 select year(birthday) from emp;(2)子查询多个SQL命令的组合,把一个SQL命令的结果作为另一个命令的条件; eg:查询高于平均工资的男员工 select * from emp where sec=1 && salary>(select avg(salary) from emp); eg:查询和Tom同一年出生的员工 select * from emp where year(birthday)=(select year(birthday) from emp where ename="Tom") && ename!="Tom";(3)多表查询查询的列分布在不同的表中时,用多表查询(前提:表和表之间必须有关联); eg:查询所有员工的姓名及部门名称 select emp.ename,dept.dname from emp,dept where emp.deptId=dept.did;select ename,dname from emp left outer join dept on deptId=did;
0
0
0
浏览量2017
青椒肉丝加点糖

JavaScript基础(一)js环境搭建、变量常量、数据类型及转换、运算符

一、JS开发环境的搭建        JavaScript 开发环境分为浏览器端和服务器端。所谓浏览器端就是 JS 代码通过浏览器自带的 JS 解释器来执行,典型代表就是五大浏览器:谷歌、火狐、edge、safari、欧朋。浏览器端执行需要创建一个 .js 文件和一个 .html 文件,然后将 .js 文件嵌入到 .html 文件中。<script src="01.js"></script>嵌入之后用浏览器打开.html文件即可。        服务器端则需要用到 Node.js,它是运行在服务器端的开发环境。需要使用时下载安装,执行方式也较为简单快捷,只需在命令提示符 cmd 下输入:node 空格  然后拖拽要运行的文件。如下:那么,如何检测自己是否安装Node了呢?在cmd命令提示符下输入node -v; 如果显示出版本号,则表示Node已成功安装。二、变量和常量        变量是存储数据的容器;常量同变量一样用于存储数据,但常量声明以后不允许重新赋值。        声明变量使用关键字var,声明常量使用关键字const。示例://变量声明 var x = 1;//表示在内容中开辟一块空间并命名为x,把1保存至这个空间中 var y = 2; var ename = '张三';//使用字符串时需要加引号 //常量声明 const pi = 3.14;三、数据类型       五大原始类型:数值型、字符串型、布尔型、未定义型、空数值型 number,包括二进制、八进制和十进制。 var n1 = 10;//10进制 var n2 = 012;//8进制 var n3 = 0xa;//16进制 var n5 = 3.1415E+2;//浮点型字符串型 string,被引号包含的数据即为字符串。 var str1 = 'abc'; var str2 = '8';布尔型 Boolean,只有两个值:true、false,通常用于保存只有两个状态的数据,例如是否在线、是否登录、一些运算符的结果等。未定义型 undefined,只有一个值 undefined,代表一个空值,例如声明了变量未赋值。空 null,只有一个值 null,类型为 object,通常结合对象一起使用检测数据类型需要用到 typeof,使用方法如下:var p = null;//定义一个变量为空 console.log(p,typeof p);//打印并用typeof检测数据类型,显示为null四、数据类型的转换首先是隐式转换,它是运算过程中自动产生的数据转换,其实是自动调用了Number函数(1)数字+字符串   数字转换为字符串后拼接(2)数字+布尔型   布尔型转换为数字,true--1,false--0(3)布尔型+字符串   布尔型转换为字符串后拼接(4)undefined+数字  undefined转为NaN(5)减乘除时,数据自动转为数值var n1 = 2 + '3';//23 var n2 = 2 + true;//3 var n3 = 'zxc' + false;//zxcfalse var n2 = '3' - 1;//2 var n3 = '2' * true;//2第二个是强制转换,需要用到函数(1)强制转换为数值型 Number( )var n1 = Number("1"); //1 var n1 = Number(true); //1 var n2 = Number(false); //0 var n3 = Number(undefined); //NaN var n4 = Number(null); //0 var n5 = Number("1a"); //NaN(2)强制转换为整型 parseInt( ) ,强制将字符串和小数转为整型var p1 = parseInt("3.14"); //3 var p2 = parseInt("6.18a"); //6 var p3 = parseInt("a6.18"); //NaN var p4 = parseInt(5.9); //5(3)强制转换为浮点型 parseFloat( ) ,强制将字符串转换为浮点型var f1 = parseFloat("3.14"); //3.14 var f2 = parseFloat("6.18a"); //6.18 var f3 = parseFloat("6a"); //6 var f4 = parseFloat("a6.18"); //NaN(4)数值和布尔型强制转为字符串 toString( )var num = 5; var str = num.toString( ); //"5"五、运算符        在学习运算符之前,先来了解以下“表达式”的定义:由数据本身或者由运算符连接的操作数据组成的形式称为表达式,也就是说,运算符所连接的数据均称为表达式。1. 算数运算符        即我们平常所用的加(+)、减(-)、乘(*)、除(/),还有取余(%)、自增(++)、自减(--)。加减乘除以及取余较为简单,不做探讨。通过一组代码来理解自增和自减:var a2 = 5; var a3 = a2++;//先将a2的值赋给a3,再自增 console.log(a2,a3);//6 5var a4 = 7; var a5 = ++a4;//a4先自增,再赋值给a5 console.log(a4,a5);//8 8        可以看出,如果自增用在变量后面,则是先使用变量的值参与计算,随后再进行变量加1;而如果自增用在变量前面,则是先将变量进行自增以后再参与计算,自减同理。2. 比较运算符等于“==”只比较两者的值是否相同,全等于“===”同时比较类型和值;不等于“!=”只比较值是否不同,不全等于“!==”同时比较类型和值,有一个不等即为 true;数字与字符串比较时,字符串转为数值;字符串之间比较时,比较首个字符的 Unicode 码;NaN 和任何值比较均返回 false,NaN == NaN 也为 false;console.log(2 == '2');//== 只比较值的大小,都为2,所以显示true console.log(2 === '2');//=== 比较值和类型,值虽然都为2,但前者为数值型,后者为字符串,所以显示false3. 逻辑运算符&& 逻辑与,关联的两个条件都为true,结果为true|| 逻辑或,关联的两个条件有一个为true结果即为true  ,! 逻辑非,取反 eg:!true = false逻辑运算符中比较重要的为短路逻辑:var a = 2; a > 3 && console.log(num);        如上代码,a 的值为 2,逻辑与判断中,第一个表达式为 a>3,而 2 不大于 3,说明此处为false,由于这里使用的运算符为逻辑与 &&,只有前后两个条件都为 true 时整体才为 true,所以第二个表达式就没有 必要再运行了,此时就是发生了短路逻辑。换句话说,短路逻辑的看重点就是在于是否执行第二个表达式。4. 位运算符        模拟计算机底层的运算,先将数据转为2进制进行运算,运算结束后再将结果转回10进制& 按位与,上下两位都是1,结果为1,否则为0;| 按位或,上下两位有一个1则结果为1;^ 按位异或,上下两位不同为1,相同为0;>> 按位右移,删除末尾的位数(原基础上除以2再取整);<< 按位左移,在末尾补0(原基础上乘以2)。//按位与 console.log(3 & 5);//011 & 101 == 001 == 1 console.log(5 & 8);//0101 & 1000 == 0000 == 0 //按位或 console.log(4 | 7);//100 | 111 == 111 == 7 //按位异或 console.log(6 ^ 9);//0110 ^ 1001 == 1111 == 15 //按位右移 console.log(9 >> 1);//1001 >> 1 == 0100 == 4 //按位左移 console.log(5 << 1);//101 << 1 == 1010 == 105. 赋值运算符        所谓赋值运算,就是先进行运算,再进行赋值var a = 1; a += 3;//4 a = a + 3;//46. 三目运算符一目运算符:由一个运算符连接的一个操作数据或者表达式  !  ++  --二目运算符:由一个运算符连接的两个操作数据或者表达式三目运算符:由两个运算符连接的三个操作数据或者表达式        格式:条件表达式 ? 表达式1 : 表达式2;如果条件表达式为 true,执行表达式1,如果条件表达式为false,执行表达式2。var a = 1,b = 2; a > b ? console.log('对') : console.log('错');        在以上函数中,a为1,b为2,首先判断a是否大于b,如果大于,则执行 console.log('对'),如果小于,则执行 console.log('错')。所以此语句输出结果为:错。
0
0
0
浏览量2015
青椒肉丝加点糖

Node.js(一)概述、全局对象/函数、node各模块使用介绍

一、Node.js概述1. 对比JS        JS运行在客户端,存在多种解释器,有代码兼容性问题;Node.js运行在服务器端,只有一种解释器,没有代码兼容性问题。两者有相同自定义对象和内置(ES)对象,不同的宿主对象。JS用于开发浏览器端的交互效果;Node.js 用于服务器端的开发,例如:数据库访问,其他服务器的调用。其实就是,JS负责前端,Node.js负责后台。2. 下载安装        安装node只需在官网直接下载安装即可。官网:Node.js中文版:Node.js 中文网3. 运行 Node.js        运行方式有两种,打开命令提示行,脚本模式:node 文件;交互模式:node 回车(进入交互模式)要知道 node 属于单线程的运行逻辑,支持数万个并发连接,适合做基于社交网络的大规模 web 应用,不适合做 CPU 密集型应用。二、全局对象1. global - 用于检测一个变量或者函数是否为全局        JS(浏览器)下的global对象名称为 window,在 Node.js 下,一个脚本文件不属于全局作用域。在JS下,一个脚本属于全局作用域,所以存在全局污染。var a = 1; //Node.js下: console.log( global.a );//undefined 不是全局作用域 //JS下: alert( window.a );//1 a为全局作用域2. console - 控制台对象,用于输出console.log(1);     //输出日志console.info(2);    //输出消息console.warn(3);   //输出警告console.error(4);   //输出错误console.time( m ); //开始计时console.timeEnd( m ); //结束计时(开始计时与结束计时所提供的参数 m 要保持一致)浏览器输出效果如下:3. process - 进程,用于查看Node.进程        计算机上任何的软件运行都有相应的进程;process.arch         查看当前CPU架构process.platform  查看当前的操作系统process.version    查看Node.js的版本号process.pid          查看当前Node.js的进程编号process.kill( )        结束指定编号的进程4. Buffer - 缓冲区,常用于保存网络传输时的资源        缓冲区是内存中临时保存数据的区域;Buffer.alloc( 6,'abc涵' );  //创建Buffer,分配空间并存储数据,每个汉字占3个字节buf.toString( )                 //将Buffer转为字符串三、全局函数 - 定时器函数一次性定时器开启:var timer = setTimeout(回调函数,间隔时间)  //间隔时间到,调用一次回调函数清除:clearTimeout(timer);//一次性定时器 var timer = setTimeout(function(){ console.log('boom!!!'); //执行三秒后输出“boom!!!” },3000); //清除 clearTimeout(timer);周期性定时器开启:let timer = setInterval(回调函数,间隔时间)  //每隔一段时间,调用一次回调函数清除:clearInterval(timer);//周期性定时器 var timer = setInterval(function(){ console.log('滴滴'); //每两秒打印一次“滴滴” },2000); console.log(1); //清除 clearInterval(timer);立即执行定时器会将回调函数放入到事件队列,当主程序完成后会立即执行;nextTick早于setImmediate.开启:let timer = setImmediate(回调函数)清除:clearImmediate(timer)开启:process.nextTick(回调函数) nextTick不能清除定时器的回调函数是在程序最后执行的。四、模块的分类1. 自定义模块        在Node.js下每一个文件代表一个模块,每个模块是一个独立的功能体。举例:(模拟  主模块main.js;功能模块circle.js)//1.在功能模块中编写功能函数 function length(r){ return 2 * Math.PI * r;//周长 } function area(r){ return Math.PI * Math.pow(r,2);//面积 } //2.在功能模块中将要导出的内容放入默认的空对象 module.exports = { a:length, //将函数lengeh导出,导出的名字为a b:area //将函数area导出,导出的名字为b }; //3.在主模块中使用require函数将功能模块引入主模块 let obj = require('./circle.js'); console.log(obj.a(7).toFixed(2)); console.log(obj.b(8).toFixed(2));2. 第三方模块(包和NPM)        包是指目录模块,通常表示第三方模块;下载网址:npm;NPM 则是被用于管理包的工具,在Node.js安装的时候会附带安装。 切换命令行路径: 方法1方法2(推荐)(1)cd 目录的路径(2)盘符名称:如果涉及到盘符的变化才需要使用第(2)步在要进入的目录的空白位置按住Shift,单击鼠标右键,选择”在此处打开powershell窗口“ npm的使用:npm可以下载安装、卸载、升级、上传第三方模块3. 核心模块(1)querystring 模块        查询字符串:浏览器端向服务器端查询数据的一种方式,位于浏览器的地址栏,querystring 模块用于处理网址中查询字符串的工具模块;使用前需要先导入 querystring 模块:const querystring = require('querystring');parse( )将查询字符串解析为对象,最终获取数据//引入querystring模块 const querystring = require('querystring'); //console.log(querystring); //查询字符串 let str = 'kw=笔记本&price=4000'; //获取传递的数据 //解析为对象 let obj = querystring.parse(str); console.log(obj.kw); console.log(obj.price);(2)URL        统一资源定位,互联网上的任何资源(html、css、图形、数据......)都有对应的URL。eg:http://www.codeboy.com:9999/products.html?kw=戴尔new URL( )将一个URL解析为对象,获取URL中的各个部分let obj = new URL('https:/www.tmooc.cn:443/course/web.html?did=2106&cname=node.js'); let obj1 = obj.search.slice(1); let obj2 = querystring.parse(obj1); console.log(` 编号:${obj2.did} 名称:${obj2.cname} `);(3)fs模块        文件系统模块:用于文件操作,分为文件形式和目录形式;使用前需要先导入fs模块:const fs = require('fs');statSync(文件路径)查看文件的状态mkdirSync(目录的路径)创建目录rmdirSync(目录的路径)移除目录,但不能移除有文件的目录//引入fs模块 const fs = require('fs'); //查看文件状态 let s = fs.statSync('./04'); console.log(s); //创建目录 fs.mkdirSync('./mydir'); //删除目录 fs.rmdirSync('./mydir');4. 三种模块的引用方式
0
0
0
浏览量396
青椒肉丝加点糖

Node.js(二)node 核心模块 fs、HTTP模块、express框架

一、核心模块(FS模块)        fs 模块是文件系统模块:用于文件操作,分文件形式和目录形式,使用前需先导入 fs 模块:const fs = require('fs');1. 常用API:2. 同步和异步//同步:在主线程中执行,会阻止后续代码的执行,通过返回值获取结果 let s = fs.statSync('./01_homework.js'); console.log(s);//异步:在一个独立的线程执行,不会阻止主线程中后续代码执行,结果以回调函数形式获取,最终放入事件队列 fs.stat('../Day02',(err,s)=>{ //形参err指可能产生的错误结果 if (err){ throw err; } //s表示成功的结果 console.log(s); //查看是否为文件 console.log(s.isFile( )); //查看是否为目录 console.log(s.isDirectory( )); });3. 文件流(1)createReadStream( )  创建可读取的文件流,分段读取数据(2)createWriteStream( )  创建可写入的文件流(3)pipe( )  管道,可以将读取的文件流添加到写入的文件流//引入fs模块 const fs = require('fs'); //创建一个可读取的文件流 let rs = fs.createReadStream('./2018061133.rar'); //创建一个可写入的文件流,即使文件不存在也会自动创建 let ws = fs.createWriteStream('./2018061101.rar'); //把读取的文件流通过管道添加到写入的文件流 rs.pipe(ws);二、HTTP模块1. HTTP协议        超文本传输协议,是客户端浏览器和Web服务器之间的通信协议。由四部分组成:(1)通用的头信息(general)  Request URL:要请求的资源        Request Method:对资源的操作方式        get获取        post新建        delete删除        Status Code: 响应的状态码:                1**:接受了请求,还没做出响应                2**:成功响应                3**:响应的重定向,发生跳转                4**:客户端错误                5**:服务器端错误(2)响应的头信息(response)        Location:要跳转的URL,通常结合状态码302来使用        Content-Type:内容类型,解决中文乱码 text/html;charset=utf-8(3)请求的头信息(request)(4)请求体,只有涉及到数据传递才会出现。2. HTTP模块        可以用来创建WEB服务器。//1.创建WEB服务器 const http = require('http'); //引入HTTP模块 const app = http.createServer( ); //创建web服务器 app.listen(8080); //设置端口 //2.接收请求做出响应 app.on('request',(req,res)=>{ req 请求的对象 req.url 请求的服务器端的资源 req.method 请求的方法 res 响应的对象 res.writeHead( ) 设置响应的状态码和头信息 res.write( ) 设置响应的内容 res.end( ) 结束并发送响应 })三、express框架        express简化了已有的功能,增加了之前没有的功能,基于项目开发,属于第三方模块,需要先下载安装:npm install express       它的特点是基于Node.js平台,快速、开放、极简的WEB开发框架。1. 路由        浏览器发来的请求,服务器根据请求的方法和请求的URL做出的响应,路由最终处理特点的请求;路由是由请求的方法、请求的URL、回调函数三个要素组成的。2. 使用步骤(1)创建服务器const express = require('express'); //引入express第三方模块 const app = express( ); //创建WEB服务器 app.listen(8080); //设置端口(2)添加路由        有三种添加方式://添加路由:处理首页的请求 //请求的URL:/index 请求的方法:get app.get('/index',(req,res)=>{ res.send('这是首页!'); }); //添加路由:跳转 app.get('/study',(req,res)=>{ res.redirect('https://www.tmooc.cn/'); }); //添加路由:响应文件 app.get('/list',(req,res)=>{ res.sendFile(__dirname + '/1.html'); });req请求对象res响应对象res.send( )设置响应的内容并发送res.redirect( )设置响应的重定向并发送res.sendFile( )设置响应的文件并发送,使用绝对路径 __dirname(3)请求对象和响应对象        即数据传递,有GET传递、POST传递、路由传参get传递:eg: //添加路由,接收按钮提交的请求 app.get('/mysearch',(req,res)=>{ //console.log(req.url,req.method); console.log(req.query); res.send('搜索成功'); });req.method获取请求的方法req.url获取请求的URLreq.query获取URL中查询字符串的数据,格式为对象post传递:eg: //新建路由(post /mylogin) app.post('/mylogin',(req,res)=>{ req.on('data',(chunk)=>{ //chunk 传递的一段数据 console.log(chunk.toString()); var obj = querystring.parse(chunk.toString()); console.log(obj); }); res.send('post方法请求成功'); }); 路由传参:eg: //新建路由,获取包的详情介绍(get /package) app.get('/package/:pname',(req,res)=>{ console.log(req.params); res.send('这是包的详情介绍'); });总结:
0
0
0
浏览量1625
青椒肉丝加点糖

JavaScript基础(三)函数、作用域

一、函数        函数是一个功能体,提供若干个数据,返回处理结果用于封装重复执行的代码。有系统函数和自定义函数之分。1. 系统函数转数值 Number ( );转整型 praseInt ( );转浮点型 parseFloat ( );警示框 alert ( );输入款 prompt ( );isNaN :检测一个值是否为NaN,用于检测用户输入的值是否为数值型。执行过程中,会隐式将数据转换为数值型,是NaN(不是数字)则返回true,否则返回false。isFinite:检测一个值是否为有限值,只有无穷(infinity)是无限值。是有限值返回true,不是有限值返回false。eval ( ) :执行字符串中的表达式。  2. 自定义函数的创建(1)创建普通函数//格式: function 函数名称 ( ) { 函数体 } //调用方式: 函数名();         PS:函数体就是封装的重复执行的代码;创建函数以后,函数体的代码不会执行,函数每调用一次,代码才会执行一次。(2)创建带有参数的函数//格式: function 函数名称 (参数列表) { //此处参数用于接收外部传递的数据(形参) 函数体 } //调用方式: 函数名称 (参数列表); //此处参数为实际传递的数据(实参)PS: 实参会赋值给形参,实参的数量和形参的数量可以不同,如果形参未被赋值则为undefined。(3)创建带有返回值的函数//格式: function 函数名称 (参数列表) { 函数体 return 值; } //调用方式: 函数名称 (参数列表);   PS:return后的值为返回值,该值是什么,调用函数后的结果就是什么,如果函数中没有return或者return后不加任何值,则返回结果为undefined,return执行后,就会结束函数的执行而且它能直接放到一个表达式的内部。        return 与 break 的区别:return 用于函数中,结束函数的执行。break 用于循环或者 switch-case,结束循环或者 switch-case 的执行。3. 递归        递归是指在函数内部调用自身这个函数,默认是一个死循环。在使用时需要有边界条件,要结合 return 使用。如下,通过一道例题来解释://用递归求斐波那契数列第n项的值 function fib(n){ //边界条件:当n为1或者n为2的时候返回1 if (n === 1 || n === 2){ return 1; } //第n项的值返回 第n-1项 + 第n-2项 的值 return fib(n-1) + fib(n-2); } console.log( fib(6) );//输出值为8PS:斐波那契数列,第一项和第二项为1,从第三项开始每项的值为前两项之和,如:1,1,2,3,5,8,13,21......首先创建带有参数 n 的函数 fib,n 代表数列的第 n 项,因为斐波那契数列的前两项为1,所以判断 n 为1或者 n 为2时返回1。除前两项之外,剩余的返回该项的前两项之和即(n-1)项和(n-2)项之和。直接调用 fib(n-1)+fib(n-2) 就是使用了递归的思想,调用函数本身。函数的递归需要注意一点:JavaScript 的运行特点是单线程,无法充分利用 CP U的内核,深层次的递归嵌套 JS 则会非常缓慢,所以递归并不是在任何情况下都适用。4. 匿名函数        匿名函数就是没有函数名称的函数 function ( ){ }(1)创建匿名函数var fn = function( ) { } 函数表达式方式(变量名称即函数名称) function fn( ) { } 函数声明方式对比匿名函数和函数名称( ):        函数名称  本质上就是一个变量,保存了一个函数        函数名称( );  调用一个函数,执行函数体中的代码,得到函数的返回值对比函数声明和函数表达式 :        函数声明存在函数的提升,可以先写调用再写创建        函数表达式只是提升变量的声明,不提升赋值,必须先写创建再调用(2)匿名函数的自调用(function(){ })();匿名函数自调用的目的是创建一个函数作用域,防止全局污染。全局污染:全局变量访问范围大,对其他变量带来的影响。举例:(function (){ var num = 2; console.log(num); })();函数体中变量num的值为2,进行自调用后打印 num。(3)回调函数        将函数以参数的形式传递,传递的这个函数就是回调函数。如下://回调函数 function tao(madai){ console.log('开始第1棒'); console.log('到达第1棒终点'); //madai = dong; //传递的函数被madai接收 //调用madai,意味着调用传递的参数 madai(); } function dong(){ console.log('开始第2棒'); console.log('到达第2棒终点'); } //此处dong作为参数进行传递,所以dong就是回调函数 tao(dong); tao(function(){ console.log('第三棒开始'); }); console.log(typeof tao);//function二、作用域        全局作用域:在函数以外的就是全局作用域,声明的变量为全局变量,在任意的作用域下都可以访问到全局变量。        函数作用域:在函数内的为函数作用域,声明的变量为局部变量,局部变量只能在当前的作用域下访问到。在函数作用域下又有全局函数与局部函数之分,在全局作用域下创建的函数就是全局函数,可以在任意作用域下访问;在局部作用域下创建的函数就是局部函数,只能在当前作用域下访问。特别注意:在程序执行前,会将 var 声明的变量提升到变量所在作用域的最前面,但只提升声明,不提升赋值,这是变量提升;在程序执行前,会将整个函数提升到所在作用域的最前面,这是函数提升。函数提升优先于变量提升。//全局作用域 var a = '北京';//全局变量 function s(){ //函数作用域 var b = '海淀区';//局部变量 console.log(a); } shi(); console.log(b); function h(){ //函数作用域 var c = '石景山区';//局部变量 }在函数以外的就是全局作用域,所以声明的变量 a 就是全局变量。函数 s 和 h 以内的为函数作用域,所以在它们内部声明的变量 b、c 全部为局部变量。a 为全局变量,即使在函数 s 的作用域下进行打印依然能够成功,因为它是全局变量。而 b 和 c 均为局部变量,只有才函数以内打印才能成功。
0
0
0
浏览量2015
青椒肉丝加点糖

jQuery(二)修改元素、查找元素

一、修改元素        和 DOM 相同,可修改元素的 内容、属性、样式 ,仍然注意凡是和修改有关的函数,都一个函数两用。1. 修改内容(1)元素开始标签到结束标签之间的原始的 HTML 内容//DOM 元素.innerHTML //jQuery $元素.html("新内容") //无“新内容”时表示获取元素的内容,有则表示将原内容修改为新内容(一函数两用)(2)元素开始标签到结束标签之间的纯文本内容//DOM 元素.textContent //jQuery $元素.text("新内容")(3)表单元素的值//DOM 元素.value //jQuery $元素.val("新值")举例:使用元素内容实现表单验证;<body> <h1>操作元素的内容和值</h1> <form action=""> 用户名:<input name="uname"> <span></span><br> 密码:<input type="password" name="upwd"> <span></span><br> <input type="submit" value="提交注册信息"> </form> <script src="js/jquery-1.11.3.js"></script> <script> //正确时,使用图片:"<img src='img/ok.png'>" //姓名错误时: "<img src='img/err.png'>用户名必须介于3~9位之间!" //密码错误时: "<img src='img/err.png'>密码必须介于6~8位之间!" //DOM 4步 // 验证用户名 //1. 查找触发事件的元素 // 触发事件的元素是文本框,文本框失去焦点时进行验证 $(":text") //2. 绑定事件处理函数 .blur(function () { var $this = $(this); //3. 查找要修改的元素 //查找当前文本框旁边的span元素 var $span = $this.next(); //4. 修改元素 // 4.1获得当前文本框的内容 var value = $this.val(); // 4.2进行验证 if (value.length >= 3 && value.length <= 9) { // 4.3修改span的内容 $span.html(`<img src='img/ok.png'>`); } else { $span.html(`<img src='img/err.png'>用户名必须介于3~9位之间!`); } }) // 验证密码 // 1.查找触发事件的元素 // 触发事件的为密码框 $(":password") // 2.绑定事件处理函数 .blur(function () { var $this = $(this); // 3.查找需要修改的元素 // 当前密码框跟前的span元素 var $span = $this.next(); // 4.修改元素 // 4.1先获取密码框的内容 var value = $this.val(); // 4.2进行验证 if (value.length >= 6 && value.length <= 8) { $span.html(`<img src='img/ok.png'>`); } else { $span.html(`<img src='img/err.png'>密码必须介于6~8位之间!`); } }) </script> </body>2. 修改属性(1)字符串类型的 HTML 标准属性//DOM/ //旧核心DOM/ 元素.getAttribute("属性名") 元素.setAttribute("属性名","新值") //新HTML DOM 元素.属性名=新值 //jQuery $元素.attr("属性名","新值") $元素.prop("属性名","新值")举例:点击图片切换下一张;<body> <h1>操作元素的属性</h1> <img src="img/1.jpg" alt="1"> <script src="js/jquery-1.11.3.js"></script> <script> //DOM 4步 // 1. 查找触发事件的元素 // 查找img $("img") // 2. 绑定事件处理函数 .click(function () { // 3. 查找要修改的元素 // 修改img本身 var $this = $(this); // 4. 修改元素 // 4.1取出当前img元素中alt属性值转为整数 var alt = parseInt( $this.attr("alt") ); // 4.2如果属性值<4,就++;否则变回1 if (alt < 4) { alt++; } else { alt = 1; } // 4.3.3将新的alt值拼成图片路径,放入当前img的src属性中 $this.attr({ src: `img/${alt}.jpg`, alt: alt }); }) </script> </body>(2)bool 类型的 HTML 标准属性//DOM //HTML DOM 元素.属性名 //jQuery $元素.prop("属性名",新bool值)(3)自定义扩展属性//DOM //旧核心DOM: 元素.getAttribute() 元素.setAttribute() //HTML5: 元素.dataset.属性名 //jQuery $元素.attr()举例:点小图片,切换大图片;<body> <img src="img/1.jpg" data-click data-target="img/1-l.jpg" class="my-small"> <img src="img/2.jpg" data-click data-target="img/2-l.jpg" class="my-small"> <img src="img/3.jpg" data-click data-target="img/3-l.jpg" class="my-small"> <img src="img/4.jpg" data-click data-target="img/4-l.jpg" class="my-small"> <hr /> <img src="img/1-l.jpg" class="my-big"> <script src="js/jquery-1.11.3.js"></script> <script> //点击小图片,下方my-big中显示大图片 //DOM 4步 // 1. 查找触发事件的元素 // 查找所有带有data-click属性的img元素 $("[data-click]") // 2. 绑定事件处理函数 .click(function () { // 3. 查找要修改的元素 // 修改下方大图 var $big = $(".my-big"); // 4. 修改元素 // 4.1获得当前点击的img的data-click属性值保存的大图片路径 var src = $(this).attr("data-target"); // 4.2将大图路径设置给大图的src属性 $big.attr("src", src); }) </script> </body>3. 修改样式//DOM //修改内联样式 元素.style.css属性="新值" //获取完整样式 getComputedStyle(元素) //jQuery //获取css属性值、修改css属性值 $元素.css("css属性","新值") //如果.css()中没有给新值,则.css()底层自动执行getComputedStyle()操作,获取属性值 //如果.css()中给了新值,则.css()底层自动执行.style.css属性,执行修改操作批量修改一个元素的多个css属性://DOM 元素.className="class名" //只能整体替换所有class,不便于修改其中某一个class //jQuery $元素.addClass("className") //添加一个class $元素.removeClass("className") //去除一个class $元素.hasClass("className") //判断是否有某个calss $元素.toggleClass("className") //在有或没有一个class之间来回切换举例:实现双态按钮;<head lang="en"> <meta charset="UTF-8"> <title></title> <style> .btn { padding: 5px 10px; border-radius: 3px; border: 1px solid #aaa; outline: none; } .up { background: #fff; color: #333; } .down { background: #ddd; color: #fff; } </style> </head> <body> <button class="btn up">双态按钮</button> <script src="js/jquery-1.11.3.js"></script> <script> //双态按钮: 让按钮的class在up和down之间切换 //DOM 4步 //1. 查找触发事件的元素 $(".btn") //2. 绑定事件处理函数 .click(function () { //3. 查找要修改的元素 var $this = $(this); if ($this.hasClass("down")) { $this.removeClass("down") } else { $this.addClass("down") } //$(this).toggleClass("down") //等价于if else //4. 修改元素 }) </script> </body>二、按节点间关系查找1. DOM 两种关系,六个属性(1)父子关系元素.parentElement //父元素 元素.children //所有直接子元素 元素.firstElementChild //第一个直接子元素 元素.lastElementChild //最后一个直接子元素(2)兄弟关系元素.previousElementSibling //前一个兄弟元素 元素.nextElementSibling //后一个兄弟元素2. jQuery两种关系,八个属性(1)父子关系$元素.parent() //父元素 $元素.children() //所有直接子元素 $元素.children("选择器") //只选择符合要求的个别直接子元素 $元素.find("选择器") //选择所有后代中符合要求的元素 $元素.children(":first-child") //第一个直接子元素 $元素.children(":last-child") //最后一个直接子元素(2)兄弟关系$元素.prev() //前一个兄弟 $元素.prevAll("选择器") //之前所有兄弟: $元素.next() //后一个兄弟 $元素.nextAll("选择器") //之后所有兄弟 $元素.siblings("选择器") //除当前元素之外,其余所有兄弟元素 案例:标签页效果;<head> <meta charset="UTF-8"> <style> .tabs { list-style: none; padding: 0 } .tabs a { text-decoration: none; color: #000; padding: 6px 12px; display: inline-block; } .tabs>li { float: left; border-bottom: 1px solid #000; } .tabs>.active { border: 1px solid #000; border-bottom: 0; } </style> </head> <body> <h1>使用属性选择器实现标签页头的切换</h1> <ul class="tabs"> <li class="active"> <a data-toggle="tab" href="#">十元套餐</a> </li> <li> <a data-toggle="tab" href="#">二十元套餐</a> </li> <li> <a data-toggle="tab" href="#">三十元套餐</a> </li> </ul> <script src="js/jquery-1.11.3.js"></script> <script> //DOM 4步 //1. 查找触发事件的元素 // 查找带有data-toggle属性,且属性值为tab的所有标签按钮 $("[data-toggle=tab]") //2. 绑定事件处理函数 .click(function () { //3. 查找要修改的元素 //需要修改的是 a标签的父级元素以及父级的兄弟元素 //4. 修改元素 var $this = $(this); // 4.1先为父级元素添加.active属性 $this.parent().addClass("active"); // 4.2在为父级元素的其他兄弟元素取消.active属性 $this.parent().siblings().removeClass("active"); //4.1和4.2可以合二为一(链式) //$this.parent().addClass("active").siblings().removeClass("active"); }) </script> </body>效果如图,每点击一个套餐,就会切换到当前套餐下。
0
0
0
浏览量664
青椒肉丝加点糖

JS 高级(七)ES6解构、class、promise

ES6: (ECMAScript第六个版本)1. 解构(destruct)在旧 js 中,要想使用对象中的成员或数字中的元素,必须带着"对象名."或"数组名[ ]"前缀。但是在实际开发中,对象或数组的嵌套结构可能很深,这样的话前缀就可能写很长: "对象名.子对象名.子对象名....",非常麻烦。而解构方式就是用来来减少数组或对象的嵌套结构,便于使用。解构分为三种:(1)数组解构数组解构用于从一个复杂的数组中只提取出需要的元素单独使用,格式如下: var [变量1, 变量2, ...] = 数组;右边数组中相同下标位置的元素值会自动赋值给=左边相同下标位置的变量,一一对应;变量1 = 数组[0];变量2 = 数组[1];要注意此处的 [ ] 并不带表创建一个新数组,仅仅是将个变量“装扮”成数组的样式。举例:从数组中解构出年、月、日;<script> var arr = [2021, 9, 3, 33]; // 解构 // 提取出数组中年月日三个值使用 // var [a, b, c] = arr; // 如果不要年,只要月日 var [, b, c] = arr; // console.log(`今年是${a}年`); console.log(`本月是${b}月`); console.log(`今天是${c}日`); </script>(2)对象解构对象解构用于从一个大的对象中只提取出个别属性值单独使用,格式如下:var { 属性名1:变量1, 属性名2:变量2,... } = 对象;当 : 左右两边的名字相同时,ES6为我们提供了简写方式:如果 : 左边的属性名刚好和 : 右边的变量名相同,则只需要写一个即可;此时一个名字就起到了两两个作用,既当属性名进行配对、又当变量名进行接值。简写后格式如下:var {属性名1, 属性名2, ...} = 对象;举例:解构出对象中的姓名和年龄单独使用;<script> var lilei = {sname: "李雷",sage: 21} // 解构 // var {sname: sname,sage: sage} = lilei; // 简写 //一个名字两用:既当属性名配对;又当变量名接值 var {sname,sage} = lilei console.log(`我叫${sname},今年${sage}岁`); </script>(3)参数解构单靠参数默认值,无法解决任意一个形参不确定有没有的情况。只要实参值不确定没有,但是又要求实参值必须传给指定的形参,顺序不能乱,就要用用参数解构。格式如下://定义函数时: function 函数名({ 属性名1: 形参1, 属性名2: 形参2, ... : ... }){ 函数体 } //调用函数时: 函数名({ 属性名1: 实参值1, 属性名2: 实参值2, ... : ... })简写后格式如下://定义函数时: function 函数名({ 属性名1 = 默认值1, 属性名2 = 默认值2, ... : ... }){ 函数体 } //调用时: 函数名({ 属性名1: 实参值1, 属性名2: 实参值2, ... : ... })举例:定义订套餐函数,用户可任意更换套餐中菜品;<script> // 定义一个点套餐的函数 function order({ zhushi = "香辣鸡腿堡", xiaochi = "烤鸡翅", yinliao = "可乐" }) { console.log(` 您点的套餐为: 主食:${zhushi} 小吃:${xiaochi} 饮料:${yinliao} `); } // a点默认套餐 order({}); // b自定 order({ zhushi: "牛肉汉堡", xiaochi: "鸡米花", yinliao: "雪碧" }) // c只换主食 order({ zhushi: "烤全鸡" }) // d只换小吃 order({ xiaochi: "正新鸡排" }) </script>打印结果如下:2. class在旧 js 中,构造函数和原型对象是分开定义的,这样不符合"封装"概念;class 是程序中专门集中保存一种类型的所有子对象的统一属性结构和方法定义的程序结构。所以今后只要在 es6 中创建一种新的类型,包含构造函数 + 原型对象方法,都要用 class 来创建。定义 class 的方法:a. 先用 class{ } 包裹原构造函数+原型对象方法;(虽直接放在 class{} 内的方法定义,其实还是保存在原型对象中的)b. 原构造函数名升级为整个 class 的名字,所有构造函数统一更名为 "constructor";c. 原型对象中的方法,不再加 prototype 前缀,也不用=function,直接简写为: 方法名(){ ...}。使用 class:var 对象名=new class名(属性值,...);虽说用了 class,但本质并没有变:构造函数中的属性,依然会成为子对象的自有属性;直接定义在 class 中的方法,依然保存在子对象的原型对象中;子对象依然使用 _ _proto_ _ 指向原型对象。举例:定义学生类型 class;<script> // 定义学生类型,描述所有学生的统一结构和功能 class Student { constructor(sname, sage) { this.sname = sname; this.sage = sage; } intr() { console.log(`我是${this.sname},我今年${this.sage}岁。`); } } // 创建一个学生对象 var lilei = new Student("李雷", 21); console.log(lilei); lilei.intr(); </script>但是上述用法也有一定的不足,若多个子对象共用相同的属性值,属性值应该放在哪里?虽然直接在 class 中定义的方法,都默认保存在原型对象中。但是直接在 class 中定义的属性,却不会成为共有属性,不会保存在原型对象中,而是成为每个子对象的自有属性。       在旧 js 中,是和共有方法一起放在原型对象中;而为了和其它主流开发语言尽量一致,ES6的 class 放弃了在原型对象中保存共有属性的方式。而是改为用静态属性 static 保存!静态属性不需要创建子对象,单靠类型名就可直接访问的属性,就称为静态属性;今后在ES6中,如果希望所有子对象,都可使用一个共同的属性值时,都要用静态属性代替原来的原型对象属性。静态属性定义与调用格式如下://定义静态属性: class 类型名{ static 共有属性名=属性值 ... ... } //访问静态属性: 类型名.静态属性注意访问静态属性时不可写成 this.静态属性 。标有 static 的静态属性,都保存在构造函数对象身上。因为构造函数在程序中不会重复,所以静态属性也不会重复;任何时候,任何地点,访问一个类型的静态属性,永远访问的都是同一份!举例:使用静态属性替所有子对象保存共用的班级名;<script> //定义学生类型,描述所有学生的统一结构和功能 class Student { // 定义静态属性,可以多个对象共用 static className = "初一2班"; constructor(sname, sage) { this.sname = sname; this.sage = sage; } intr() { console.log(`我是${this.sname},我今年${this.sage}岁`); } } // 创建学生对象 var lilei = new Student("李雷", 21); var hmm = new Student("韩梅梅", 20) console.log(lilei); console.log(hmm); lilei.intr(); hmm.intr(); // 一年后,初一升初二 Student.className = "初二2班"; lilei.intr(); hmm.intr(); console.log(Student); //log 默认输出的是Student构造函数的函数体(内容),不是对象结构 console.dir(Student); //dir 不输出函数的内容,而是输出对象在内存中的存储结构 </script>两种类型间的继承两种 class 之间可能包含部分相同的属性结构和方法定义,这时候就应该用到继承。进行继承的方法:(1)额外创建一个父级 class; i. 父级 class 的构造函数中包含子类型 class 中相同部分的属性结构定义; ii. 父级 class 的原型对象中包含子类型 class 中相同部分的方法定义; iii. 既然父级 class 中保存了相同的属性结构和方法定义,则子类型 class 中,就可以删除所有重复的属性结构和方法定义;(2)让子类型 class 继承父类型的 class; i. 设置子类型的原型对象继承父类型的原型对象;class 子类型 extends 父类型{ ... } ii. 使用 super 关键字,调用父级的父级类型的构造函数。举例:使用类型间继承,实现飞机大战游戏中敌机和降落伞类型的定义,并创建敌机对象和降落伞对象;<script> //定义爷爷class,保存共有属性结构和方法 class enemy { constructor(x, y) { this.x = x; this.y = y; } fly() { console.log(`目标飞到x=${this.x},y=${this.y}的位置。`); } } class Plane extends enemy { constructor(x, y, score) { super(x, y); this.score = score; } getScore() { console.log(`击落敌机得${this.score}分!`); } } class Jls extends enemy { constructor(x, y, ming) { super(x, y); this.ming = ming; } getMing() { console.log(`击落降落伞,得生命值${this.ming}!`); } } var p1 = new Plane(255, 255, 20); var p2 = new Jls(222, 125, 1) p1.fly(); p1.getScore(); p2.fly(); p2.getMing(); </script>3. Promisepromise 是专门保证多个异步任务必须顺序执行的一种特殊方式;在实际开发中,经常需要让多个异步任务顺序执行,而单纯先后调用多个异步函数的话,异步函数各自执行各自的,互不干扰,互相之间也不会等待,是错误的。解决以上问题可以用回调函数,举例:使用回调函数保证多个异步任务顺序执行; <script> function zhangsan(box) { console.log(`张三起跑!`); setTimeout(function () { console.log(`张三跑到了终点!`); box(); }, 6000) } function lisi(box) { console.log(`李四起跑!`); setTimeout(function () { console.log(`李四跑到了终点!`); box(); }, 4000) } function wangwu() { console.log(`王五起跑!`); setTimeout(function () { console.log(`王五跑到了终点!`); }, 2000) } zhangsan(function () { lisi(function () { wangwu(); }); }); </script>但是用回调函数的话,如果要先后执行的任务多了,就会形成很深的嵌套结构——回调地狱,不仅极其不优雅,而且极其不便于维护。这种情况下,就需要用到 promise 来代替回调函数。步骤:(1)定义前一项任务function 前一项任务(){ return new Promise( function(开关){ 原异步任务 异步任务最后一句话 调用开关()//开关通向后面的.then,自动执行.then中的下一项任务 } ) }(2)连接前后两个异步任务前一项任务().then( 后一项任务 ) //注意最后一项任务不要再加()两个任务之间也可以进行传参://前一项任务: function 前一项任务(){ return new Promise( function(开关){ var 变量=值 调用开关( 变量 ) } ) } //后一项任务: function 后一项任务(形参){ //形参=前一项任务中的变量值 }举例:使用 Promise 模拟接力跑传接力棒;<script> function zhangsan() { return new Promise( function (open) { var JieLiBang = "张三的接力棒"; console.log(`张三拿着${JieLiBang}起跑!`); setTimeout(function () { console.log(`张三跑到了终点!`); open(JieLiBang); }, 6000) } ) } function lisi(JieLiBang) { return new Promise( function (open) { console.log(`李四拿着${JieLiBang}起跑!`); setTimeout(function () { console.log(`李四跑到了终点!`); open(JieLiBang); }, 4000) } ) } function wangwu(JieLiBang) { console.log(`王五拿着${JieLiBang}起跑!`); setTimeout(function () { console.log(`王五跑到了终点!`); }, 2000) } zhangsan().then(lisi).then(wangwu); </script>(3)错误处理,格式如下://前一项任务: function 前一项任务(){ return new Promise( function(成功的开关, 失败的开关){ var 变量=值 原异步任务 异步任务最后一句话 如果异步任务执行成功 调用成功的开关( 变量 )//此处开关通.then(),自动执行.then中的下一项任务 否则如果一部任务执行失败 调用失败的开关(错误提示信息)//此处开关通最后的.catch(),后续.then()不再执行。 } ) } //调用时: 前一项任务() .then(下一项任务) .then(...) .catch(function(错误提示信息){ 错误处理代码 })举例:假设有人在跑步过程中摔倒了,要添加错误处理;<script> function zhangsan() { return new Promise( function (resolve, reject) { var JieLiBang = "张三的接力棒"; console.log(`张三拿着${JieLiBang}起跑!`); setTimeout(function () { if (Math.random() < 0.5) { console.log(`张三拿着${JieLiBang}到达了终点!`); resolve(JieLiBang); } else { reject(`张三摔倒了!!`); } }, 6000) } ) } function lisi(JieLiBang) { return new Promise( function (resolve, reject) { console.log(`李四拿着${JieLiBang}起跑!`); setTimeout(function () { if (Math.random() < 0.5) { console.log(`李四拿着${JieLiBang}跑到了终点!`); resolve(JieLiBang); } else { reject(`李四摔倒了!!`); } }, 4000) } ) } function wangwu(JieLiBang) { console.log(`王五拿着${JieLiBang}起跑!`); setTimeout(function () { console.log(`王五跑到了终点!`); }, 2000) } zhangsan() .then(lisi) .then(wangwu) .catch(function (msg) { console.log(msg); console.log(`出现紧急状况,比赛终止!!!!`); }); </script>(4)Promise对象三大状态 (记忆)a:当异步任务执行过程中,整个 new Promise() 对象处于 pending(挂起) 状态;b:当异步任务成功执行完,调用成功的开关函数时,整个 new Promise() 对象切换为 fulfilled(成功) 状态,new Promise() 会自动调用 .then() 执行下一项任务;c:当异步任务执行出错,调用失败的开关函数,整个 new Promise() 对象切换为 rejected(出错) 状态,new Promise() 会自动调用 .catch() 执行错误处理代码。在行业中,这两个开关常用(规范):正确的开关:resolve(同意继续)失败的开关:reject(拒绝继续)
0
0
0
浏览量1312
青椒肉丝加点糖

CSS(二)元素基础样式、字体属性、文本属性

一、元素基础样式1. 尺寸和单位        宽度width和高度height使用长度单位:px、pt、rem、em、%等;        max-width 最大宽度,max-height 最大高度;        min-width 最小宽度,min-height 最小高度,不允许出现负值。        一般PC端网页使用 px 或者 pt,移动端使用 %、em、rem、vw、vh 等响应式单位。2. 颜色(1)英文颜色        常用 red、green、blue、yellow、orange、pink、purple、gold 等,还有透明色transparent。(2)十六进制颜色        格式为 #rrggbb,1、2 位代表红色范围;3、4 位代表绿色范围;5、6 位代表蓝色范围。值的范围为 0-9,a-f。如果三组都是相同的值,可简写,如:#00ff00 --> #0f0。(3)RGB颜色        格式为 rgb(r,g,b);  r 代表红色色值;g 代表绿色色值;b 代表蓝色色值。        取值范围为0~255 之间的256个数。        rgba();a代表透明度,取值 0~1 之间的数字,0 代表完全透明 rgb(255, 5, 251); rgba(15, 2, 15, 0.5);(4)web 安全色        安全色是用于网页的标准色彩,它比标准的 rgb 色彩要少,如果网页设计的时候用了非 web 安全色,那这个网页在不同的电脑显示出来可能是不同的颜色。3. 边框(1)边框属性border-width边框宽度border-style边框样式,solid实线,dashed虚线,dotted点点border-color边框颜色(2)边框的方向border-bottom下边框border-top上边框border-left左边框border-right右边框(3)简写        border:边框宽度  边框样式  边框颜色(最常用)  border:30px solid green; border-bottom:10px solid blueviolet;(4)案例:三角形的 CSS 写法.sjx { width: 0; height: 0; border: 50px solid transparent; border-bottom-color: black; }4. 元素的分类(1)元素的显示属性display: block;以块级元素方式显示display: inline;以内联元素方式显示display: inline-block;属于行内元素,但以块级显示,俗称行内块display: none;不显示display: table;以 table 方式显示(不是重点)(2)元素特性5. 显示和隐藏属性二、字体属性1. 字体大小——font-size: 30px;   设置字号,        字体大小可以使用不同的单位,如 px、pt、em、rem、vw等等,不允许负值像素。几种常见取值如下:px  像素pt  磅em  父级元素的倍数em参照的是父级字号的比例,如1em代表父级字号*1rem  根标签的倍数rem参照的是根标签(html)的指定字号vw  视窗尺寸        Google浏览器字体大小默认为16px,最小12px。2. 字体系列——font-family: "华文新魏";   设置所需要的字体。        推荐字体系列:(可直接复制使用)<!--移动端项目:--> font-family:Tahoma,Arial,Roboto,"Droid Sans","Helvetica Neue","Droid Sans Fallback","HeitiSC",sans-self; <!--pc端(含Mac)项目:--> font-family:Tahoma,Arial,"Helvetica Neue","Hiragino Sans GB",Simsun,sans-self; <!--移动和pc端项目:--> font-family:Tahoma,Arial,Roboto,"Droid Sans","Helvetica Neue","Droid Sans Fallback","HeitiSC","Hiragino Sans GB",Simsun,sans-self;3. 字体字重(粗细)——font-weight: 400;   设置字体的粗细。       值为介于 1 和 1000 之间的数字类型值,必须要是 100 的倍数。常用关键词:normal(400 默认)、bold(粗体700)、lighter(细体300)。4. 字体样式——font-style: italic;   设置字体的样式。font-style: normal;  默认正常font-style: italic;  斜体5. 简写 格式:font:字体样式 字重 字号 字体系列(不可改变顺序)font: italic 600 20px "仿宋";三、文本属性1. 字体颜色        color:颜色的色值;2. 文本对齐方式——text-align: center;left  默认,左对齐center居中对齐right  右对齐该属性针对块级元素中的内联元素,它需要写在父级(块级元素)中,不能写在子元素中。3. 文本的行高—— line-height: 70px;       行高=文字上下间距+文本高度;使单行文字在父元素垂直居中时使文本的行高等于父元素的高度即可。4. 文本线条修饰text-decoration: none;无线条(常用于将a标签的默认下划线去掉)text-decoration: underline;下划线text-decoration: overline;上划线text-decoration: line-through; 删除线5. 首行缩进——text-indent: 2em;6. 文本换行       正常文字拥有默认的 white-space:normal 属性,当达到定义的宽度之后就会自动换行,而连续的英文字符和数字不能换行,在 div 中英文字母之间没有空格的话,它会默认为这是一个英文单词,所以一次性输出不换行white-space: nowrap;  不换行word-wrap:break-word;  强制换行7. 文本溢出.d9 { width: 300px; /* 限宽 */ white-space: nowrap; /* 强制不换行 */ overflow: hidden; /* 多余部分不显示 溢出部分隐藏 */ text-overflow: ellipsis; /* 文本溢出显示 */ }8. 文字阴影格式:text-shadow:x 轴偏移量  y 轴偏移量  模糊半径的大小  颜色值text-shadow: 10px 10px 5px brown;9. 垂直对齐方式——vertical-align: middle;        垂直对齐针对的是该元素前后的内联元素或者文字,而不是本身。常用关键值:vertical-align: middle;居中对齐vertical-align: top;顶部对齐vertical-align: bottom;底部对齐vertical-align: baseline;基线对齐(默认)
0
0
0
浏览量1885
青椒肉丝加点糖

JS 高级(三)继承、多态、ES5严格模式

一、面向对象1. 继承 只要将方法定义放在构造函数中,那么每次 new 时都会执行 function,这样就会反复创建相同函数的多个副本,导致浪费内存。如果将来发现多个子对象都要使用相同的功能和属性值时,都可以用继承来解决。父对象中的成员,子对象无需重复创建就可直接使用,就像使用自己的成员一样,这就是继承。js 中的继承都是通过原型对象实现的,原型对象就是替所有子对象集中保存共有属性值和方法的特殊父对象。当多个子对象需要使用相同的功能和属性值时,都可将相同的功能和属性值集中定义在原型对象中。原型对象不用自己创建,在定义构造函数时,程序自动附赠我们一个空的原型对象。构造函数中都有一个自带的属性 prototype,指向自己配对的原型对象——构造函数 .prototype。new 的第二步自动让新创建的子对象,继承构造函数的原型对象。new 会自动为子对象添加_ _proto_ _ 属性,指向构造函数的原型对象。向原型对象中添加新的共有属性和方法时,只能是强行赋值:添加新属性或方法后,用子对象访问对象的成员时,js引擎先在子对象内部查找自有的属性;如果子对象没有,则 js 引擎会自动延 _ _proto_ _ 属性去父元素查找。如果在父元素中找到了想要的属性或方法,则和访问子对象的方法一样调用。示例: 将所有子对象共用的方法保存进构造函数里<script> // 构造函数 function Student(sname, sage) { this.sname = sname; this.sage = sage; } // 强行向student类型的原型对象(prototype)中添加一个所有子对象共用的的方法intr Student.prototype.intr = function () { console.log(`我叫${this.sname},我今年${this.sage}岁`); } // 用构造函数反复创建多个相同结构但内容不同的对象 var lilei = new Student("李雷", 45); var hmm = new Student("韩梅梅", 30); console.log(lilei); console.log(hmm); lilei.intr(); hmm.intr(); console.log(lilei.__proto__ == Student.prototype); //true说明原型对象是子元素的父级 console.log(hmm.__proto__ == Student.prototype); //true </script>自有属性和共有属性(1)获取属性值时,毫无差别,都可用: 子对象.属性名。如果 js 引擎发现要使用的属性不在子对象中,则自动延 _ _proto_ _ 属性向父对象继续查找要用属性。(2)修改属性值示例: 为所有学生添加共有的班级名属性,并修改;<script> function Student(sname, sage) { this.sname = sname; this.sage = sage; } Student.prototype.className = "初一二班"; var lilei = new Student("lilei", 11); var hmm = new Student("hmm", 12); // 修改自有属性 lilei.sname = "zhangsan"; console.log(lilei); console.log(hmm); console.log(lilei.className, hmm.className); // 一年后,两位同学一起升级(修改共有属性) // 1.错误方式 // lilei.className = "初二二班"; // 此方式不会修改原型对象中的共有属性,而会给当前子对象添加一个同名的自有属性,导致该子对象与其他子对象无法继续保持同步。 // 2.正确方式,必须修改原型对象 Student.prototype.className = "初二二班"; console.log(lilei.className, hmm.className); </script>内置类型的原型对象内置类型就是 ES 标准中规定的,浏览器已经实现,我们可以直接使用的类型。包括十一种String、Number、Boolean、Array、Date、RegExp、Error、Function、Object、Math(不是类型,而是一个{ }对象)、global(全局作用域对象,在浏览器中被window代替)。每种类型一定有2部分组成:构造函数,负责创建该类型的子对象;原型对象,负责为该类型所有子对象集中保存共有的属性值和方法定义。除 Math 和 global 之外,其余也都可以通过 new 创建子对象。想要查看该类型中有哪些 API,可以使用 -- 类型名.prototype -- 。如果经常使用的一个功能,但是原型对象中没有提供,我们可以自定义一个函数保存到原型对象中。举例:为数组类型添加求和的方法<script> var array1 = [1, 2, 4, 5, 8, 8]; var array2 = [125, 48, 48, 478, 2584]; // 创建自定义函数 Array.prototype.sum = function () { console.log("调用自定义函数sum"); // 数组求和套路 // 1.定义变量临时保持求和的值 var sum = 0; // 2.遍历数组元素 for (i = 0; i < this.length; i++) { // 3.将遍历出的元素值累加 sum += this[i]; } // 4.返回累加结果 return sum; } // 调用sum console.log(array1.sum()); console.log(array2.sum()); </script>原型链原型链是由多级父对象逐级继承形成的链式结构,保存着:一个对象可用的所有属性和方法,控制着属性和方法的使用顺序,采用就近原则,先子级后父级。<script> function Student(sname, sage) { this.sname = sname; this.sage = sage; } // 向Student原型对象中添加一个toString方法 Student.prototype.toString = function () { // 此处this指将来调用这个toString()的点前的某个学生的类型的子对象. return `{sname:${this.sname},sage:${this.sage}}`; } var lilei = new Student("lilei", 12); var arr = [1, 2, 3]; var now = new Date(); console.log(lilei.toString()); console.log(arr.toString()); console.log(now.toString); </script>2. 多态 多态指同一个函数,在不同情况下表现出不同的状态,包括重载和重写。3. 自定义继承(1)只更换一个对象的父对象,两种方法://示例:更换一个对象的父对象 <script> function Student(sname, sage) { this.sname = sname; this.sage = sage; } var lilei = new Student("李磊", 11); var hmm = new Student("韩梅梅", 12); var father = { money: 1000000000000, car: "infiniti" } // 1.只更换一个对象的父对象 // 更换hmm的继承父对象为father // hmm.__proto__ = father;//不推荐 Object.setPrototypeOf(hmm, father); //推荐 console.log(hmm.money, hmm.car); console.log(lilei.money, lilei.car); console.log(lilei); console.log(hmm); </script>(2)批量更换多个子对象的父对象,只需要更换构造函数的 prototype 属性就可以,但必须在创建子对象之前更换!//示例: 批量更换两个子对象的父对象<script> function Student(sname, sage) { this.sname = sname; this.sage = sage; } var father = { money: 1000000000000, car: "infiniti" } // 2.批量更换多个子对象的父对象 // 必须在创建子对象之前更换构造函数的原型对象 Student.prototype = father; var lilei = new Student("李磊", 11); var hmm = new Student("韩梅梅", 12); console.log(hmm.money, hmm.car); console.log(lilei.money, lilei.car); console.log(lilei); console.log(hmm); </script>二、ES5(ECMAScript 第5个版本)1. 严格模式在旧的js中有很多广受诟病的缺陷,严格模式就是比旧的js运行机制要求更严格的新运行机制,今后企业中所有代码都要运行在严格模式下。启用严格模式只需在当前代码段的顶部添加:   "use strict"; 即可。严格模式有四个新规定:a:禁止给未声明过的变量赋值;旧的js中,如果强行给未声明过的变量赋值,不会报错,而是,自动在全局设置该变量,这就造成了全局污染。而严格模式中,强行给未声明过的变量赋值,会报错,这样就减少了因为写错变量名造成的全局污染!举例:给未声明的局部变量赋值<script> function send() { var gf; // 假设不小心写错了变量名 qgf = "今晚308,w84u"; //直接报错qgf is not defined console.log(`女朋友收到${gf}`); } send(); console.log(`全局中:${qgf}`); </script>未使用严格模式,打印如下,本来想给“女朋友”发送的消息,却发到了全局,但系统不报错。启用严格模式,在代码段首行添加"use strict";<script> // 启用严格模式 "use strict"; // 禁止给未声明过的变量赋值 function send() { var gf; // 假设不小心写错了变量名 qgf = "今晚308,w84u"; //直接报错qgf is not defined console.log(`女朋友收到${gf}`); } send(); console.log(`全局中:${qgf}`); </script>打印如下,此时直接报错,便于我们发现程序中的问题并修改。b. 静默失败升级为错误;静默失败指程序运行不成功,但是也不报错,这样极其不利于调试程序,严格模式:会将绝大部分静默失败都升级为报错。<script> // 静默失败升级为错误 var eric = { aid: 1001, sanme: "斯塔克" } // 这里将eid属性设置为只读 Object.defineProperty(eric, "eid", { writable: false }) // 试图篡改 eric.eid = 1002; console.log(eric); </script>打印如下:即使将eid设置为只读,属性值仍被修改,但不报错。启动严格模式后打印如下:c. 普通函数调用中的 this 不再指 window,而是指 undefined,在旧 js 中普通函数调用中的 this 默认指 window,极容易造成全局污染。启用严格模式后普通函数调用中的 this 指向 undefined,不再指 window,可防止因为错误使用 this 而导致的全局污染。<script> // 启用严格模式 "use strict"; // 普通函数调用中的this不再指window,而是指undefined function Student(sname, sage) { console.log(this); this.sname = sname; //报错 Cannot set property 'sname' of undefined this.sage = sage; } var lilei = new Student("李蕾", 12); // 假设忘记写new var hmm = Student("韩梅梅", 13); console.log(lilei); console.log(hmm); console.log(window); </script>d. 禁用了 arguments.callee,arguments.callee; 是在一个函数内,获得当前函数本身的一种特殊关键字(递归)。在函数内写死当前函数名,一旦外部函数名改变,内部函数名忘记修改,则程序立刻报错造成紧耦合,所以在函数内使用 arguments.callee 代替写死的函数名。在运行时,自动获得当前函数本身(松耦合)。而且递归重复计算量太大,效率极低,如果递归调用严重影响程序的性能时,就要用循环来代替递归。举例:分别使用递归和循环实现计算斐波那契数列第 n 个数//递归方式 <script> // 禁用了arguments.callee // 斐波那契数列 // 前两个数是都是1,从第三个数开始,每个数都是它相邻的前两个数的和 function f(n) { if (n < 3) { return 1; } else { return arguments.callee(n - 1) + arguments.callee(n - 2); } } console.log(f(10));//55 </script>//循环方式 <script> function f(n) { if (n < 3) { return 1; } else { var f1 = 1, f2 = 1, fn; for (var i = 3; i <= n; i++) { fn = f1 + f2; f1 = f2; f2 = fn; } return fn; } } console.log(f(10)); //55 </script>补充:this 4种指向;(1)obj.fun()  fun中的this指 .前的obj对象(谁调用指谁);(2)new Fun()  Fun中的this指new创建的新对象;(3)fun() 或 (function(){ ... })() 或 回调函数 thisz默认指windozw;(4)原型对象(prototype)中的this指将来调用这个共有函数的.前的某个子对象(谁调用指谁)。
0
0
0
浏览量361
青椒肉丝加点糖

JavaScript基础(五)js中常见错误类型及解决、ES6介绍

本期为补充内容,包括 JavaScript 中常见的错误类型以及解决方式和 ES6。ES6 在前端初始阶段不内容会用太多,在这里只进行简单介绍,仅作了解。详细后续阶段跟进。一、JS中常见错误以及错误处理1.SyntaxError:语法错误        代码编写不符合规范,例如出现了中文符号、缺少括号等(出错后整体代码不再运行)。2.ReferenceError:引用错误        使用了未声明的变量(影响之后的代码执行)。3.TypeError:类型错误        当前调用的方法或函数不是一个函数形式(影响之后的代码执行)。4.自定义错误:程序员自己指定的错误          格式:throw  错误内容(影响之后的代码执行)。处理方式:try{ //可能会产生错误的代码 }catch(err){ //try中出现错误才会执行 //将错误信息保存到err中 //执行错误处理 }举例如下:var age = 98; if (age < 18 || age > 60){ throw '非法的年龄';//抛出错误 } //错误处理:出现错误后不再影响后续代码 try{ //可能会产生错误的代码 }catch(err){ //try中出现错误才会执行 //将错误信息保存到err中 }二、ES6        ES6全称ECMAScript6,是js第六套标准规范,提供了更多且更为强大的功能,使得JavaScript编程语言更为完善。以下介绍一些相关概念:1. 块级作用域大括号之间的语句块例如if else语句、while语句、for循环等带之间的语句。块级作用域下let和const声明都是局部的,外部无法访问,可防止全局污染2. 参数增强参数增强简单说就是为参数设置默认值,在参数没有赋值时用默认值代替。格式如下:function(a,b,c = 0){ //es6设置默认值方法为在形参处赋值 b = b || 0; //此处为es6之前设置默认值的方式 }3. 箭头函数        简化了匿名函数的写法,但不等价于匿名函数,格式:( ) => { 函数体 }。function sort(a,b){ return a - b; } //简化后 sort(a,b) => { return a - b; });4. 模板字符串        解决了字符串的拼接问题 ,格式:` 模板字符串 ${ JS表达式 }  ` let title = '联想拯救者'; let price = 6699; let isOnsale = '1'; console.log( ` 标题:${title} 价格:${price.toFixed(2)} 是否在售:${isOnsale ? '是' : '否'} ` );
0
0
0
浏览量1395
青椒肉丝加点糖

H5画布 canvas(二)绘制文字、图片、坐标系,canvas颜色和样式,canvas绘制环境

1. 绘制文字ctx.font;设置文本内容的字体属性,使用方式与 css font 相同ctx.textAlign;设置文本内容的对齐方式        start:默认,文本在指定的位置开始        end:文本在指定的位置结束        center:文本的中心被放置在指定的位置         left:文本左对齐         right:文本右对齐ctx.textBaseline;设置绘制文本时使用的当前文本基线      alphabetic:默认,文本基线是普通的字母基线      top:文本基线是 em 方框的顶端      hanging:文本基线是悬挂基线       middle:文本基线是 em 方框的正中心      ideographic:文本基线是 em 基线      bottom:文本基线是 em 方框的底端ctx.fillText();填充文本ctx.strokeText();绘制文本(无填充)ctx.measureText();返回包含指定文本宽度的对象接下来我们在上文饼状图案例的基础上绘制文字:<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>绘制饼状图&文字</title> <style></style> </head> <body> <div> <canvas id="table"></canvas> </div> </body> <script> var canvas = document.getElementById('table'); //获取canvas标签 var ctx = canvas.getContext('2d'); //获取上下文 //设置画布宽高、边框(边框也可使用CSS选择器来设定) canvas.width = 600; canvas.height = 400; canvas.style.border = '2px solid #000'; //定义饼状图数据 var data = [{ 'value': 0.2, 'color': '#149985', 'title': '城市A' }, { 'value': 0.3, 'color': 'red', 'title': '城市B' }, { 'value': 0.4, 'color': 'blue', 'title': '城市C' }, { 'value': 0.1, 'color': '#999999', 'title': '城市D' }, ] //绘制饼状图 var tempAngle = -90; //记录绘制到了哪个角度 for (var i = 0; i < data.length; i++) { ctx.beginPath(); //每一次循环都绘制不同的扇区,所以都要开启新状态 ctx.moveTo(200, 200); //每一次都回到圆心点开始绘制 var angle = data[i].value * 360; //每一个扇区的角度 ctx.fillStyle = data[i].color; //颜色填充按照数据遍历 var startAngle = tempAngle * Math.PI / 180; //起始角度 var endAngle = (tempAngle + angle) * Math.PI / 180; //每一次的结束角度=起始角度+扇区角度 ctx.arc(200, 200, 100, startAngle, endAngle); //绘制文字 var txt = data[i].value * 100 + '%'; //获取要绘制的文字 var x, y; //文字坐标 var txtAngle = tempAngle + 1 / 2 * angle; //文字位置的角度 = 起始角度 + 扇区的一半 //计算文字坐标 x = 200 + Math.cos(txtAngle * Math.PI / 180) * (100 + 20); y = 200 + Math.sin(txtAngle * Math.PI / 180) * (100 + 20); ctx.font = '20px "微软雅黑"'; //设置字体 if (txtAngle > 90 && txtAngle < 270) { //设置y轴左边的文字结束位置对齐,防止文字显示不全 ctx.textAlign = 'end'; } ctx.fillText(txt, x, y); //填充文字 ctx.fill(); tempAngle = tempAngle + angle; //每次绘制完一次扇区起始角度为原角度加该扇区角度 } </script> </html>加上文字的饼状图如下:在这里注意我们计算文字文字位置时用到了两个公式:200 为圆心点的位置,cos 计算 x 轴方向的位置,sin 计算 y 轴方向的位置,100 为半径长度,20 是文字到圆周的距离;该公式通用。x = 200 + Math.cos(txtAngle * Math.PI / 180) * (100 + 20); y = 200 + Math.sin(txtAngle * Math.PI / 180) * (100 + 20);2. 绘制图片(drawImage)(1)基本绘制方法ctx.drawImage(img,x,y);绘制图片基本方式,x y 为绘片左上角的坐标, img是绘制图片的dom对象 ctx.drawImage(img,x,y,width,height);绘制图片并规定宽高 ctx.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);绘制图片并在画布上定位被裁剪的部分,sx,sy 裁剪区域的左上角坐标, swidth 裁剪图片的宽度,sheight 裁剪的高度,其余属性相同如下简单案例:(2)案例:序列帧动画(通过图片裁剪,实现人走路的动态效果)        图片裁剪常用育在一张具有多种元素的图片中裁剪出其中一个元素,例如在一张具有多个人物的图片中抠出其中一个人物等等。接下来我们通过一张人走路的序列帧图来实现动态效果;原始序列帧图片如下:过程也很简单,就是使用到了循环计时器 setInterval,循环裁剪图片中的每一帧,并清除之前裁剪的所有元素,只展示最新的元素,实现动态效果。<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>序列帧动画</title> <style></style> </head> <body> <div> <canvas id="table"></canvas> </div> </body> <script> var canvas = document.getElementById('table'); //获取canvas标签 var ctx = canvas.getContext('2d'); //获取上下文 //设置画布宽高、边框(边框也可使用CSS选择器来设定) canvas.width = 600; canvas.height = 400; canvas.style.border = '2px solid #000'; //绘制图片 var img = new Image(); //创建图片DOM对象 img.src = 'img/zoulu.jpg'; //图片路径,设置后img对象会立即加载图片 img.onload = function () { var framIndex = 0; setInterval(function () { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, framIndex * 80, 0, 50, 400, 200, 100, 80, 300); //绘制图片 framIndex++; //添加到下一帧 framIndex %= 5; }, 1000 / 6); } </script> </html>案例效果如下:3. 绘制坐标系<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>绘制坐标系</title> <style></style> </head> <body> <div> <canvas id="table"></canvas> </div> </body> <script> var canvas = document.getElementById('table'); //获取canvas标签 var ctx = canvas.getContext('2d'); //获取上下文 //设置画布宽高、边框(边框也可使用CSS选择器来设定) canvas.width = 600; canvas.height = 400; canvas.style.border = '2px solid #000'; //画笔起点 var x0 = 100; var y0 = 380; var maxHeight = 390; var arrowWidth = 10; //箭头宽度 //绘制x轴 ctx.beginPath(); ctx.strokeStyle = 'blue'; ctx.moveTo(x0, y0); ctx.lineTo(500, 380); ctx.lineTo(500 - arrowWidth, 380 - arrowWidth); ctx.moveTo(500, 380); ctx.lineTo(500 - arrowWidth, 380 + arrowWidth); ctx.stroke(); //绘制y轴 ctx.beginPath(); ctx.moveTo(x0, y0); ctx.lineTo(100, 0); ctx.lineTo(100 - arrowWidth, arrowWidth); ctx.moveTo(100, 0); ctx.lineTo(100 + arrowWidth, arrowWidth); ctx.stroke(); //绘制线段 var data = [0.4, 0.5, 0.3, 0.8, 0.4, 0.6]; //假数据 var pointWidth = 380 / (data.length + 1); ctx.beginPath(); ctx.strokeStyle = 'red'; for (var i = 0; i < data.length; i++) { var x = x0 + (i + 1) * pointWidth; var y = y0 - data[i] * maxHeight; ctx.lineTo(x, y) } ctx.stroke(); </script> </html> 效果如下:4. canvas 颜色样式和阴影(了解)相关颜色样式:ctx.fillStyle;填充颜色(可支持所有格式的颜色) ctx.strokeStyle;描边颜色(可支持所有格式的颜色) ctx.strokeStyle = 'red'; ctx.strokeStyle = '#ccc'; ctx.strokeStyle = 'rgb(255,0,0)'; ctx.strokeStyle = 'rgba(255,0,0,6)';相关阴影样式(效率低、性能差,建议不使用):ctx.shadowColor;阴影颜色 ctx.shadowBlur;模糊级别,大于 1 的正整数,数值越高,模糊程度越大 ctx.shadowOffsetX;阴影距形状的水平距离 ctx.shadowOffsetY;阴影距形状的垂直距离 使用方式与 css 中类似: ctx.shadowColor = 'teal'; ctx.shadowBlur = 10; ctx.shadowOffsetX = 10; ctx.shadowOffsetY = 10; ctx.fillRect(100, 100, 100, 100);5. 复杂样式(1)渐变ctx.createLinearGradient(x0,y0,x1,y1);线性渐变,x0 y0 为起始坐标,x1 y1 为结束坐标,使用时需要添加渐变色 var grd = ctx.createLinearGradient(0, 0, 170, 0); grd.addColorStop(0, 'black'); //添加一个渐变颜色,值介于 0.0 与 1.0 之间 grd.addColorStop(1, 'white'); //添加一个渐变颜色 ctx.fillStyle = grd; //把渐变设置到填充的样式 ctx.createRadialGradient(x0,y0,r0,x1,y1,r1);圆形渐变,x0 渐变开始圆的 x 坐标,y0 渐变的开始圆的 y 坐标,r0: 开始圆的半径,x1 渐变的结束圆的 x 坐标,y1 渐变的结束圆的 y 坐标,r1 结束圆的半径 var rlg = ctx.createRadialGradient(300, 300, 10, 300, 300, 200); rlg.addColorStop(0, 'teal'); //添加一个渐变颜色 rlg.addColorStop(0.4, 'navy'); rlg.addColorStop(1, 'purple'); ctx.fillStyle = rlg; //设置 填充样式为延续渐变的样式 ctx.fillRect(100, 100, 500, 500);(2)绘制背景图ctx.createPattern(img,repeat);img 设置平铺背景的图片,repeat 背景平铺的方式 var ctx = c.getContext('2d'); var img = document.getElementById('lamp'); var pat = ctx.createPattern(img, 'repeat'); ctx.rect(0, 0, 150, 100); ctx.fillStyle = pat; // 把背景图设置给填充的样式 ctx.fill();(3)变换(重点)ctx.scale(scalewidth,scaleheight);画布缩放 ctx.translate(x,y);位移画布,发生位移后,相当于把画布的 0,0 坐标更换到新的 x,y 位置,所有绘制的新元素都被影响 ctx.rotate(angle);旋转画布6. 绘制环境的相关操作ctx.save();保存当前环境的状态,可以把当前绘制环境进行保存到缓存中 ctx.restore();返回之前保存过的路径状态和属性 ctx.globalAlpha=number;设置绘制环境的透明度,值介于0-1之间 ctx.clip();在画布的限定区域绘制,从原始画布中剪切任意形状和尺寸,一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内 canvas.toDataURL(type, encoderOptions);把 canvas 绘制的内容输出成 base64 内容,type 设置输出的类型,比如 image/png image/jpeg 等;encoderOptions 值为 0-1 之间的数字,用于标识输出图片的质量,1 表示无损压缩 var canvas = document.getElementById("canvas"); var dataURL = canvas.toDataURL(); console.log(dataURL); var img = document.querySelector("#img-demo");//拿到图片的dom对象 img.src = canvas.toDataURL("image/png"); //将画布的内容给图片标签显示
0
0
0
浏览量1923
青椒肉丝加点糖

CSS(一)概述、选择器、选择器优先级

CSS:层叠样式表(Cascading Style Sheets)是一种用来表现HTML或XML等文件样式的计算机语言。不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。  CSS 能够对网页中元素位置的排版进行像素级精确控制,支持几乎所有的字体字号样式,拥有对网页对象和模型样式编辑的能力。对前端网页的布局与美化有着广泛作用。一、CSS概述1. 前端HTML、Javascript、CSShtml:超文本标记语言。用于网页的结构搭建和页面布局。css:层叠样式表。用于网页的修饰,样式的渲染。javascript:解释型的编程语言。用于与页面的交互。2. CSS语法规范(1)内联样式        内联样式也叫行内样式,就是在 html 文件中的 html 标签中,用 style 属性样式值来完成渲染。内联样式将样式写在标签里,缺点是杂乱且不易于修改,复用性差;优点是可以指定当前标签,更加直接。<!-- 内联样式 --> <span style="样式声明"></span>2)内部样式        在网页头部<head></head>中增加一对<style></style>标签,在 style 中定义样式。特点是需要选择器查找到元素并嵌入 HTML 文件,只能在当前页面使用,优先级低于内联样式(不建议用于项目)。<head> <!-- 内部样式 --> <style> h2 { background-color: lightpink; color: red; } </style> </head>(3)外部样式        单独创建 CSS 文件,在 HTML 文件的 head 标签中引入。<head> <!-- 外部样式 --> <link rel="stylesheet href="01.css"> </head>    href 为超文本引用,引用 css 文件路径,rel 属性指文件与当前HTML的关系(必写)。外部样式所有页面都可以使用,是项目中最重要的样式使用方式。二、CSS选择器 要使用 css 对 HTML 页面中的元素实现一对一,一对多或者多对一的控制,这就需要用到 CSS 选择器。HTML页面中的元素就是通过 CSS 选择器进行控制的。1. 基础选择器(1)通用选择器:使用通配符 * ,选择 HTML 文件中所有元素。最常用的写法是清除浏览器内外边距,如下: *{margin:0;padding:0}(2)元素选择器:也叫标签选择器,直接使用标签的名字来选择 HTML 元素。权重值为1h1 {color: teal;} div {color: green;}(3)id 选择器:只针对一个元素,一般不作为样式渲染的选择器使用。#getblue {color: blue;}(4)类选择器:通过元素的类名即class值选择元素。权重值10.oz {color: purple;}.oo {color: orangered;}        一个元素可以创建多个类名,每个类名之间用空格分开即可。(5)群组选择器:将多种选择器进行组合,把不同的选择器用逗号连接.y,#mybox { background-color: yellow;}2. 关系选择器(1)后代选择器:先代元素(祖先)选择器写在前面,空格后写后代元素选择器。.item span { color: red; }(2)子代选择器:选中某个元素的直接子元素(当前元素下的第一层子元素),与后代不同的是子代选择器的范围更小。body>div>div>div { color: red; }(3)兄弟选择器.l1~li { color: blue; } .s~.nv { color: red; }        注意,前面的为参照元素,后面的为筛选元素,选中的永远是其参照元素后面的兄弟元素。(4)相邻选择器:同一层的关系选择器,可以选中参照的元素后面紧挨着的被参照元素的选择器。.o1+span { color: red; }3. 伪类选择器   伪类选择器的作用是匹配同一个元素,设置其不同状态下的样式。常用的伪类有: a:link { color: green; } div:hover { background-color: salmon; } button:hover+div { background-color: red; }4. 伪元素选择器        用于设置元素的“指定部分”的样式。::before元素最前边部分::after元素的最后边部分div::before { content: "欢迎您,"; font-weight: bolder; font-size: 26px; }需要注意content属性必须写,但值可以为空。三、CSS优先级(1)顺序读取:相同类型选择器采用顺序读取后来的优先。(2)选择器优先级:不同类选择器,按照权重原则(id选择器100,类选择器10,元素选择器 1)。(3)继承:制定样式的优先级大于继承样式的优先级。(4)多个选择器一起使用:根据权重值累加比较值后采用优先级。2. 最高优先级 - !important        直接获取最高优先级,但注意内联样式不能加 !important。用法如下:.d1{ background-color: rgb(22, 92, 161) !important; } <!-- 表示类名为d1的元素具有最高优先级 -->3. 优先级的比重大小        按引入方式:内联样式 > 内部样式 > 外部样式        按元素:id 选择器(100)> 类选择器(10)> 元素选择器(1)
0
0
0
浏览量228
青椒肉丝加点糖

JS 高级(一)RegExp、函数、重载、作用域和作用域链

一、RegExp对象        在 js 中,由于正则表达式语法与 js 的语法不相同,js 不认识正则表达式,所以需要对正则表达式进行翻译,RegExp 对象应运而生。        RegExp 对象是专门在 js 程序中保存一条正则表达式的对象。它可将正则表达式语法翻译为 js语言认识的语法,从而让正则表达式能够与 js 一起运行,实现功能。1. 创建正则表达式的方法        标准:var reg=new RegExp("正则表达式","ig");        简写:var reg=/正则表达式/ig;        其中 i 代表 ignore,忽略大小写;g 代表 global,全部所有。举例:<script> // 请用户输入消息内容 var str = prompt("请输入消息内容:"); // 定义正则表达式 // var reg = new RegExp("[我卧][草操艹]"); //常规 var reg = /[我卧][操草艹]/; //简写 // 查找是否含有敏感词 var result = str.search(reg); if (result != -1) { console.log("含有敏感词!"); } else { console.log(`他说:${str}`); } </script>2. RegExp对象提供的两个函数(1)reg.test() 专门用于验证字符串的格式是否符合要求的函数。       写法为 var 验证结果=正则表达式对象.test(要检查的字符串),需要注意的是 test() 默认只要在字符串中找到部分内容和正则匹配,就返回 true,而不要求必须从头到尾完整匹配。为了解决这个问题,需要在正则前加“^”(开头),后加"$"(结尾)。举例://手机号的验证 <script> // 输入手机号 var phone = prompt("请输入手机号"); // 定义正则 // var reg = new RegExp("^1[3-9]\\d{9}$"); var reg = /^1[3-9]\d{9}$/; //简写 var result = reg.test(phone); if (result == true) { console.log(`格式正确`); } else { console.log(`格式错误`); } </script>(2)reg.exec() 专门用正则查找字符串中所有敏感词的内容和位置的函数。        既想获得所有敏感词的内容,又想获得所有敏感词的位置时,都用 exec() 函数,如果找到一个敏感词,就会返回一个数组:        数组:[ 0: "敏感词的内容",  index: 敏感词的下标位置i ]        如果没找到,则返回 null。该函数的缺点是只查找第一个敏感词的内容和位置,所以为了查找所有敏感词内容与位置,需要用到 do-while 循环。举例://查找所有以“小”字开头的名字 <script> var str = "老师:请用小红 我的 朋友造句。小楠:小红是我的朋友。小亮:朋友!小红是我的!"; var reg = /小[\u4e00-\u9fa5]/; var arr = reg.exec(str); console.log(arr); var reg = /小[\u4e00-\u9fa5]/g;//g必须加,代表所有 do { var arr = reg.exec(str); console.log(arr); if (arr != null) { console.log(`在${arr.index}位置,找到敏感词${arr[0]}`); } } while (arr != null); </script>3. js中几种查找函数的对比二、function        函数是程序中专门保存一段可重复使用的代码段的程序结构/对象,换句话说,当一段代码可能被反复使用时,都要先定义在函数中,然后反复调用函数。1. 函数中的几个概念        形参:专门保存函数调用时所必须的数据的局部变量,当我们定义函数时发现,函数内有的数据不确定时,都要定义形参变量。要求调用者在调用函数时传入必须的数据(实参)。        返回值:即函数的执行结果,如果将来调用函数的人需要获得函数的直接结果,继续做其它操作时,就要给函数定义返回值。2. 函数的调用        var 返回值=函数名(实参值1, 实参值2, ...);(1)在内存中找到指定名称的函数,同时将实参值一一对应的赋值给函数的形参变量;(2)按函数体的描述,执行规定好的任务;(3)将函数的执行结果,返回到函数外部。//计算两个任意数的和 <script> function add(a, b) { return a + b; } var c = add(5, 5); var d = add(c, 410); var e = add(d, 50); console.log(c, d, e); </script>3. 函数的创建(1)声明方式,该方式存在声明提前,会打乱程序正常的执行方式。function b() { console.log(1); } b(); function b() { console.log(2); } b(); // 2 2 无法打印1(2)赋值方式,不存在声明提前var fun = function () { console.log(1); } fun(); var fun = function () { console.log(2); } fun(); // 1 2 正常打印4. js中函数的本质              函数其实也是一个对象,它可以赋值,可以传参,每个function底层都相当于new Function(),也就是说它们都有自己唯一的内存地址值,即使一模一样的两个函数定义,但是做比较时由于地址不同,所以结果也不同。而函数名只是一个普通的变量而已。举例:<script> // 1.函数可以赋值 var fun = function () { console.log(123); } var fun2 = fun; fun(); fun2(); // 2.函数可以传参(回调函数) function 小明(裤兜) { console.log("小明下楼吃饭"); console.log("吃完饭"); 裤兜(); } var fun1 = function () { console.log("带包子"); } 小明(fun1); var fun2 = function () { console.log("带奶茶"); } 小明(fun2); // 3.当两个对象用==比较时,比较的不是内容,而是内存地址值 var fun1 = function () { console.log(1); } var fun2 = function () { console.log(1); } console.log(fun1 == fun2); //false;输出结果虽然一样,但是地址不同 </script> 补充:函数 function 与方法的区别三、重载        相同函数名,不同形参列表的多个函数,可以在调用时自动根据传入的实参值不同,选择对应版本的函数调用,这就是重载。它可以减少函数名的个数,减轻调用者的负担。        在  js 程序中禁止两个同名函数同时存在。如果同时存在两个同名函数,则只有最后定义的一个函数才能有效,前者会被覆盖。为了解决此问题,需要用到 arguments 对象。        arguments 对象在每个函数中都有自带,直接使用即可,专门接受所有传入函数的实参值的内容。在函数内部,判断 arguments 的长度、元素值、元素类型等条件,根据传入实参值或实参个数不同,来选择执行不同的逻辑。举例://定义函数pay支持三种付款方式 <script> function pay() { if (arguments.length == 0) { console.log(`手机支付`); } if (arguments.length == 1) { console.log(`现金支付,收您${arguments[0]}`); } if (arguments.length == 2) { console.log(`刷卡支付,从账户${arguments[0]}中扣款${arguments[1]}元`); } } pay(); pay(100); pay("753159", "100"); </script>四、作用域和作用域链        作用域是一个变量的可用范围,分为两级:全局作用域,在程序的任何位置都能访问的范围,包括:一切不属于任何函数和对象的变量和函数。全局作用域中的变量为全局变量。函数作用域,函数 function{ } 范围内才能访问的区域,只有函数的{ },才能形成作用域!只要不是函数的{},都不是作用域。函数作用域中的变量为局部变量,函数的形参默认为局部变量。//判断程序的输出结果 <script> var a = 10;//全局 function fun1() { var a = 100;//局部 a++; console.log(a); //101 } fun1(); console.log(a); //10 var b = 10; function fun2() { b = 100; //只是一条赋值语句,相当于全局变量 b++; console.log(b); //101 } fun2(); console.log(b); //101 </script>作用域的原理如下: a.定义函数时:每个函数对象身上都有一个"好友列表",普通函数的好友列表只有两个格子。离自己近的格子,暂时为空,预留。离自己远的格子,保存window对象的引用关系。 b.调用函数时:临时创建函数作用域对象,并将函数作用域对象的地址,保存到好友列表中离函数近的格子里。然后在函数作用域对象中临时添加函数的局部变量。 c.调用函数过程中:每用到一个变量,js引擎都会先在离自己近的函数作用域对象中查找使用。如果函数作用域对象中找到了想要的变量,则不再去全局找;如果函数作用域对象中没有找到想用的变量,js引擎就会延好友列表继续去全局查找变量使用。 变量的使用遵循就近原则。
0
0
0
浏览量872
青椒肉丝加点糖

jQuery(三)添加/删除/替换/克隆元素、事件

一、添加/删除/替换/克隆1. 添加新元素(1)DOM三步//a.创建新的空对象 var 元素=document.createElement("标签名") //b.添加必要属性 元素.属性名=属性值 //c.将新元素添加到DOM树 //末尾追加新元素 父元素.appendChild(新元素) //插入到现有元素之前 父元素.insertBefore(新元素, 现有元素) //替换现有元素: 父元素.replaceChild(新元素, 现有元素)(2)jQuery两步//a.用HTML片段批量创建多个元素,同时设置元素的属性和内容 var $新元素=$(`HTML片段`) //b.将新元素添加到DOM树,有10个函数 //在父元素末尾追加新元素 $父元素.append($新元素) //return $父元素 $新元素.appendTo($父元素) //return $新元素 //在父元素下开头插入一个新元素 $父元素.prepend($新元素) //return $父元素 $新元素.prependTo($父元素) //return $新元素 //插入到一个现有元素之前 $现有元素.before($新元素) //return $现有元素 $新元素.insertBefore($现有元素) //return $新元素 //插入到一个现有元素之后 $现有元素.after($新元素) //return $现有元素 $新元素.insertAfter($现有元素) //return $新元素 //替换现有元素 $现有元素.replaceWith($新元素) //return $现有元素 $新元素.replaceAll($现有元素) //return $新元素2. 删除元素$元素.remove()3. 克隆元素$元素.clone()举例:点按钮添加方块,点×删除方块;<head> <style> .container { border: 1px solid #aaa; overflow: hidden; } .block { float: left; margin: 10px; border: 1px solid #aaa; background: #faa; width: 150px; height: 150px; } .block:hover { box-shadow: 0 5px 6px #000; } .close { float: right; padding: 5px; font-weight: bold; opacity: .2; cursor: pointer; } .close:hover { opacity: .5; } </style> </head> <body> <h1>添加/删除节点</h1> <button id="add-block">添加区块</button> <div class="container"></div> <script src="js/jquery-1.11.3.js"></script> <script> //一、点击按钮,添加新方块 //DOM 4步 //1. 查找触发事件的元素 //点击按钮触发事件,因为多个方块中的×都可点击,所以用事件委托优化,事件应该只绑定在父元素上一份即可 $("button") //2. 绑定事件处理函数 .click(function () { //3. 查找要修改的元素 //4. 修改元素 //4.1创建一个新的方块 $(`<div class="block"><span class="close">×</span></div>`) //4.2设置随机背景色 .css( "background-color", `rgb(${ parseInt(Math.random()*256) },${ parseInt(Math.random()*256) },${ parseInt(Math.random()*256) })` ) //4.3将新方块追加到container div下的开头位置 .prependTo(".container") }) //二、删除之前添加的方块 //DOM 4步 //1. 查找触发事件的元素 //点击按钮触发事件,因为多个方块中的×都可点击,所以用事件委托优化,事件应该只绑定在父元素上一份即可 //事件委托第1步: $(".container") //2. 绑定事件处理函数 .click(function (e) { //判断如果当前点击的元素有class close,才能继续执行操作 //事件委托第2步: e.target代替this var $tar = $(e.target); //3. 查找要修改的元素 //事件委托第3步: 判断当前元素 if ($tar.html() == "×") { $tar.parent() //4. 修改元素 .remove(); } }) </script> </body> 如图所示,点击”添加区块“按钮会在下方添加一个随机颜色的方块,点击”ד即可删除当前方块。二、事件1. 事件绑定(1)DOM 中有三种方法        a.在 HTML 中手工绑定,但该方法很繁琐且不便于维护;        b.在 js 中用赋值方式绑定,但一个事件上只能绑定一个处理函数;        c.在 js 中添加事件监听对象;元素.addEventListener("事件名",事件处理函数(){ ... }) 元素.removeEventListener("事件名",原事件处理函数(){ ... })(2)jQuery中有一种方法$元素.on("事件名",事件处理函数(){ ... }) $元素.off("事件名",原事件处理函数) //移除一个事件监听 //简写 $元素.事件名(事件处理函数)  可以使用简写的常用事件列表:   应注意在 jQuery 中绑定和移除事件需要用有名称的函数,可以同时绑定多个事件监听对象,但移除时,所有同名的事件处理函数会被一次性全部移除。举例:点按钮发射子弹,可发射多种子弹,也可移除子弹;<body> <h1>事件绑定</h1> <button id="btn1">发射子弹</button> <button id="btn2">获得奖励</button> <button id="btn3">失去奖励</button> <script src="js/jquery-1.11.3.js"></script> <script> //点btn1时,发射普通子弹 $("#btn1").click(function () { console.log(`发射普通子弹!`); }) var shoot2 = function () { console.log(`获得奖励+1`); } //点btn2时,给btn1多加一种跟踪导弹 $("#btn2").click(function () { $("#btn1").click(shoot2); }) //点btn3时,从btn1移除跟踪导弹 $("#btn3").click(function () { $("#btn1").off("click", shoot2) }) </script> </body>2. jQuery中的事件委托        当多个平级子元素都要绑定相同的事件时,就需要用到事件委托。(1)DOM 事件委托三步(重点)        a. 事件只绑定在父元素上一份;        b. e.target 代替 this ;        c. 判断当前目标元素是不是想要的。(2)jQuery事件委托三步(了解)        a. 事件绑定在父元素上一份,必须用 on() 方式绑定;        b. 不用 e.target 代替 this,jQuery 中 this 指向最初实际点击的目标元素;        c. $父元素.on("click","选择器条件",事件处理函数)。3. 页面加载后自动执行        由于网页是顺序执行的,所以放在外部js文件中的js代码,在结尾引入时是有效的,三在网页开头引入就无效。        如果想要 js 初始化操作,必须在网页内容加载完成后才能执行,不要提前执行。就要用 window.οnlοad=function(){ };凡是放在 window.οnlοad=function(){ } 中的代码,无论写在哪儿都会在整个网页内容加载完成(触发 load 事件)后,才自动执行。如下举例:<body> <button id="btn1">click me 1</button> <button id="btn2">click me 2</button> </body> <script> window.onload = function () { console.log(`当页面加载完成后自动执行。`); $("#btn1").click(function () { console.log(`别点了!`); }) $("#btn2").click(function () { console.log(`再次警告!!!`);; }) }) </script>        但是,如果两个 js 文件中都有 window.οnlοad=function(){ },则只有最后引入的一个 js 文件中的 window.οnlοad=function(){ } 会保存下来,造成覆盖。所以用到新写法,该将所有 window.οnlοad=function(){ } 都换为 window.addEventListener("load",function(){ });       还应注意,load 事件必须等待所有网页内容(HTML+JS+CSS+图片)都加载完才能触发,在网页加载过程中,有两次加载完成事件:        (1)首先仅 DOM 内容(HTML+JS)加载完成:DOMContentLoaded        (2)然后才是所有网页内容加载完成(load)        今后只要不依赖与 css 和图片的初始化操作,都应该绑定到 DOMContentLoaded 事件上。如下:window.addEventListener( "DOMContentLoaded", function(){ ... } )简写:$(document).ready(function(){ ... }) $().ready(function(){ ... }) $(function(){ ... }) //常用 $(()=>{ ... })举例:仅 DOM 内容加载完成时,就提前给按钮绑定单击事件;<body> <button id="btn1">click me 1</button> <button id="btn2">click me 2</button> </body> <script> //window.onload = function () { //window.addEventListener("load", function () { $(function () { console.log(`当页面加载完成后自动执行。`); $("#btn1").click(function () { console.log(`别点了!`); }) $("#btn2").click(function () { console.log(`再次警告!!!`);; }) }) // } //}) </script>4. 鼠标事件(1)DOMmouseover鼠标进入mouseout鼠标离开 以上两种即使反复进出子元素,也会反复触发父元素上的鼠标进出事件,存在一定的问题,新的事件为:mouseenter鼠标进入mouseleave鼠标离开 简化写法:如果同时绑定鼠标进入和鼠标离开两个事件,只需要绑定一个hover()即可,但只在 jQuery 中适用。格式如下: $元素.hover( //等同于鼠标进入mouseenter和鼠标移出mouseleave function(){ ... }, //给mouseenter function(){ ... }, //给mouseleave )举例:使用 mouseente r和 mouseover 绑定鼠标进出事件,并使用 hover 简化鼠标进出事件;<body> <div id="target"> <p>Lorem ipsum dolor sit amet</p> </div> <script src="js/jquery-1.11.3.js"></script> <script> //当鼠标进入#target时,添加class hover;当鼠标离开#target时,移除class hover // $("#target").mouseenter(function () { // $(this).addClass("hover") // }) // $("#target").mouseleave(function () { // $(this).removeClass("hover") // }) //简写 $("#target").hover(function () { $(this).toggleClass("hover") //替换函数toggleClass,表示mouseenter与mouseleave切换 }) </script> </body>5. 模拟触发        即使没有点在按钮上,也能触发按钮上的单击事件处理函数。$元素.trigger("事件名")   如果要触发的事件属于常见事件列表,还可以省略trigger(),简写为:$元素.事件名()
0
0
0
浏览量1661
青椒肉丝加点糖

H5画布 canvas(三)canvas 库 Konva.js 的使用

一、Konva 基本概念        Konva.js,全称适用于桌面/移动端应用的 HTML5 2d canvas 库,是一个HTML5 Canvas JavaScript 框架,它提供了高性能的动画,补间,节点嵌套,布局,滤镜,缓存,事件绑定(桌面/移动端)等等功能。你可以使用 Konva 在舞台上绘制图形,给图形添加事件,移动、缩放和旋转图形并且支持高性能的动画即使包含数千个图形。Konva 具有以下特点:轻量,使用方便,可适用于 PC 端和移动端;支持丰富的事件处理操作;支持类似于 jQuery 的操作方式;开源,可以随意更改;性能好。Konva 中文文档 中文API Konva Konvajs 中文文档, Konva 是一个HTML5 Canvas JavaScript 框架,它通过对 2d context 的扩展实现了在桌面端和移动端的可交互性。提供了高性能的动画,补间,节点嵌套,布局,滤镜,缓存,事件绑定(桌面/移动端)等等功能.        在 Konva 的使用中,整个视图可以看成一个舞台 stage,舞台中可以有多个层次 layer,每一层下面又可以有各种形状或者很多组 group,组下面也可以有分组或各种各样的形状 shape,如下示意图:二、Konva 的使用1. 引入 Konva        在我们的项目中使用 Konva 前需要先引入 .js 包,可以通过 <script> 标签在线引入,也可以从 CDN 下载至本地后引入;在线引入:<script src="https://unpkg.com/konva@4.0.0/konva.min.js"></script>从 CDN 下载官网 Konva.js 包: Konva.js 完整版 Konva.js 压缩版2. Konva 基本绘制步骤(1)创建一个具有 id 名的 div,用于放置舞台;<div id="container"></div>(2)创建舞台 stagevar stage = new Konva.Stage({ container: 'container', //指定放置舞台的容器 width: window.innerWidth, //设置宽高 height: window.innerHeight, })(3)创建层 layer 并将层添加至舞台;var layer = new Konva.Layer(); //创建层 layer stage.add(layer); //将层添加至舞台(4)创建要绘制的图形(此处以矩形为例); var rect = new Konva.Rect({ //创建矩形 x: 100, y: 100, opactity: 0.5, draggable: true, fill: 'red' //其余相关属性... })(5)将创建的形状添加至层并将层渲染到舞台中;layer.add(rect); //将图形添加至层 layer.draw(); //将层渲染到舞台接下来我们结合以上步骤使用 Konva 绘制一个矩形:<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>使用konva库制作一个矩形</title> <style></style> <!-- 引入Konva包 --> <script src="https://unpkg.com/konva@4.0.0/konva.min.js"></script> </head> <body> <!-- 放置舞台 --> <div id="container"></div> </body> <script> //1.创建舞台 var stage = new Konva.Stage({ container: 'container', width: window.innerWidth, //宽高(全屏) height: window.innerHeight, }) //2.创建层 var layer = new Konva.Layer(); //3.将层添加至舞台 stage.add(layer); //4.创建矩形 var rect = new Konva.Rect({ x: 100, //起始坐标 y: 100, width: 200, //宽高 height: 100, scaleX: 1.3, scaleY: 1.3, draggable: true, fill: 'red' //填充 }) //5.将矩形添加至层 layer.add(rect); //6.将层渲染至舞台 layer.draw(); </script> </html> 效果如下:三、Konva 动画1. tween 对象        使用动画时必须先实例化 Konva.tween 对象创建补间动画,然后执行 play() 运行动画;tween 是控制 Konva 对象进行动画的核心对象,它可以控制所有数字类型的属性进行动画处理,比如:x, y, rotation, width, height, radius, strokeWidth, opacity, scaleX 等。如下是一个基本的 tween 创建动画的例子:var tween = new Konva.Tween({ node: rect, //要使用动画的Konva对象 x: 300, y:300, rotation: 360, //旋转 duration: 1, //持续时间 easing: Konva.Easings.EaseIn, //动画效果 yoyo: true, //是否进行循环播放 ...... onFinish: function() { //动画执行结束后,执行此方法 } }); tween.play(); //启动动画除用 play() 方法启动动画之外,tween 还有以下参数可供使用:tween.play();播放动画 tween.pause();暂停动画 tween.reverse();动画逆播放 tween.reset();重置动画 tween.finish();立即结束动画动画的效果也有多种:Konva.Easings.Linear;线性 Konva.Easings.EaseIn;缓动,先慢后快 Konva.Easings.EaseOut;先快后慢 Konva.Easings.EaseInOut;两头慢,中间快 Konva.Easings.BackEaseIn;往回一点,然后往前冲 Konva.Easings.BackEaseOut Konva.Easings.BackEaseInOut Konva.Easings.ElasticEaseIn;橡皮筋 Konva.Easings.ElasticEaseOut Konva.Easings.ElasticEaseInOut Konva.Easings.BounceEaseIn;弹跳 Konva.Easings.BounceEaseOut Konva.Easings.BounceEaseInOut Konva.Easings.StrongEaseIn;强力 Konva.Easings.StrongEaseOut Konva.Easings.StrongEaseInOut2. 动画 to 方法的使用        在实际的开发过程中,如果每次使用动画都先实例化 Konva.tween,在 play() 启动动画,这样是很麻烦的,而且效率不高。而 Konva 也为开发者提供了更为简便的方式,那就是 to,to 其实就是对 tween 的封装。在使用 to 时我们不必再去实例化 Konva.tween 对象,直接在需要添加动画的对象后面 .to{ } 创建相关属性即可。如下是使用动画的两种方式对比:效果如下:3. 循环播放动画        循环播放主要是结合 tween 配合 onFinish 事件中的 reset()重置动画 和 play()播放动画,达到循环播放的效果。如下简单案例:<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>konva动画</title> <style> body { padding: 0; margin: 0; background-color: bisque; overflow: hidden; } </style> <!-- 引入Konva包 --> <script src="https://unpkg.com/konva@4.0.0/konva.min.js"></script> </head> <body> <!-- 放置舞台 --> <div id="container"></div> </body> <script> //创建舞台 var stage = new Konva.Stage({ container: 'container', width: window.innerWidth, //宽高(全屏) height: window.innerHeight, }) //创建层 var layer = new Konva.Layer(); //将层添加至舞台 stage.add(layer); //创建矩形 var rect = new Konva.Rect({ x: 250, y: 250, width: 100, height: 100, fill: 'red' }); layer.add(rect); layer.draw(); //tween为矩形添加动画 var tween = new Konva.Tween({ node: rect, //要进行动画的Konva对象 x: 100, y: 100, rotation: 360, //旋转360度 opactity: .1, easing: Konva.Easings.Linear, //动画效果 duration: 2, //持续时间 yoyo: true, //是否进行循环播放 onFinish: function () { //动画执行结束后执行此方法 this.reset(); //重置动画 this.play(); //播放动画 } }); tween.play(); //启动动画 </script> </html> 效果如下:四、案例:使用 Konva 绘制进度条        具体思路就是:绘制一个外部矩形,一个内部矩形,再为内部矩形添加动画,宽度由 0 变为外部矩形的宽度。<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>使用konva库制作一个进度条</title> <style> body { padding: 0; margin: 0; background-color: bisque; overflow: hidden; } </style> <!-- 引入Konva包 --> <script src="https://unpkg.com/konva@4.0.0/konva.min.js"></script> </head> <body> <!-- 放置舞台 --> <div id="container"></div> </body> <script> //创建舞台 var stage = new Konva.Stage({ container: 'container', width: window.innerWidth, //宽高(全屏) height: window.innerHeight, }) //创建层 var layer = new Konva.Layer(); //将层添加至舞台 stage.add(layer); //设置中心点 var centerX = stage.width() / 2; var centerY = stage.height() / 2; var x = 1 / 8 * stage.width(); var y = centerY; var height = 1 / 12 * stage.height(); var maxWidth = 3 / 4 * stage.width() //绘制进度条 //内部矩形 var innerRect = new Konva.Rect({ x: x, y: y, width: 100, height: height, opacity: 0.8, //透明度 fill: '#149985', cornerRadius: height / 2, //圆角 }); //将内部矩形添加至层 layer.add(innerRect); //外部矩形 var outerRect = new Konva.Rect({ x: x, y: y, width: maxWidth, height: height, stroke: 'blue', strokeWidth: 2, cornerRadius: height / 2, }); //将外部矩形添加至层 layer.add(outerRect); //为内部矩形添加动画效果 innerRect.to({ width: maxWidth, //内部矩宽度变为最大宽度 duration: 1.4, //动画持续时间 easing: Konva.Easings.StrongEaseInOut, }) //将层渲染至舞台 layer.draw(); </script> </html> 案例效果:
0
0
0
浏览量504
青椒肉丝加点糖

Node.js(三)路由器、中间件、MySQL模块、RESTful接口

一、路由器        用来管理路由,将一个模块下所有的路由放到一起,最后被WEB服务器使用。用法如下://路由器下: const express = require('express'); //引入express const r = express.Router( ); //创建路由器 r.get('/list',(req,res)=>{ //添加路由 res.send('这是用户列表'); }); module.exports = r; //导出路由器对象//WEB服务器下: const express = require('express'); //引入express const userRouter = require('./user.js'); //引入用户路由器 console.log(userRouter); const app = express( ); //创建web服务器 app.listen(8080,()=>{ //设置端口 console.log('服务器创建成功!'); }); app.use('/user',userRouter); //使用路由器,把路由器下所有的路由挂载到WEB服务器下,'/user'是为路由添加的前缀二、中间件        处于请求和响应之间,可以拦截请求,也可以做出响应。所有中间件在使用前均先创建服务器。1. 应用级中间件        就是一个函数,一旦拦截到会执行这个函数        格式:app.use(要拦截的URL,函数)app.use('/shopping',(req,res,next)=>{ //添加中间件 //获取get传递的数据 console.log(req.query); req.query.price *= 0.9; next( ); //往后执行 }); app.get('/shopping',(req,res)=>{ //添加到购物车 console.log(req.query); res.send(`商品的价格:${req.query.price}`); });2. 路由级中间件        路由器的使用        app.use(要拦截的URL,路由器) 3. 内置中间件        用于托管静态资源,如果客户端托管静态资源(html、css、js、图像......),不需要通过路由器响应,而是自动的到指定的目录下寻找。        格式:app.use(express.static(托管的目录的路径));app.use(express.static('./public'));4. 第三方中间件        属于第三方模块,使用前需要先下载安装。5. 错误处理中间件//格式:在路由中 app.get('/list',(req,res,next)=>{ next(错误信息) //把错误交给错误处理中间件 }); eg: //添加错误处理中间件,拦截所有路由中产生的错误 app.use((err,req,res,next)=>{ //err 所接收到的路由传递过来的错误信息 console.log(err); res.status(500).send({code:500,msg:'服务器端错误!'}); //响应错误 });三、MySQL模块1. 使用步骤(1)引入MySQL模块const mysql = require('mysql');(2)创建一个连接对象const c = mysql.createConnection({ host:'127.0.0.1', port:'3306', user:'root', password:'', database:'tedu' });(3)执行SQL命令c.query('select * from emp where ename=?',[str],(err,result)=>{ if(err) throw err; console.log(result); });2. 连接池   创建的一批连接,可以被反复使用,用完后会归还。(1)引入MySQL模块const mysql = require('mysql');(2)createPool( )  创建连接池对象const pool = mysql.createPool({ host:'127.0.0.1', port:'3306', user:'root', password:'', database:'tedu', connectionLimit:15 //连接池数量 });(3)query( )  执行SQL命令pool.query('select * from emp',(err,result)=>{ if (err) throw err; console.log(result); });四、RESTful接口     接口是后端为前端提供的动态资源(对数据的增删改查),而RESTful则是一种接口设计规范。1. URL http://127.0.0.1:8080/v1/emps //多个资源http://127.0.0.1:8080/v1/emps/3       //单个资源(v1版本号、emps 资源名称(复数形式)、3编号)http://127.0.0.1:8080/v1/users/login //对资源的特殊操作例如登录2. 请求方法        对资源的操作方式,包括 get(获取资源)、post(新建资源)、delete(删除资源)、put(修改资源)。3. 过滤数据eg:http://127.0.0.1:8080/v1/products?price1=4000&price2=5000   //过滤一组价格区间的数据http://127.0.0.1:8080/v1/products?pno=1&count=9                    //通过分页过滤4. 返回结果        格式为 JSON 对象:字符串形式的对象,属性名必须是双引号,属性值是字符串且必须用双引号,包含状态码(人为规定)、消息、数据。格式如下:{ "code":200, "msg":"登录成功" } { "code":200,"msg":"登录成功","data":[ ] }推荐接口工具: ApiPost
0
0
0
浏览量1032
青椒肉丝加点糖

jQuery(二)修改元素、查找元素

一、修改元素        和 DOM 相同,可修改元素的 内容、属性、样式 ,仍然注意凡是和修改有关的函数,都一个函数两用。1. 修改内容(1)元素开始标签到结束标签之间的原始的 HTML 内容//DOM 元素.innerHTML //jQuery $元素.html("新内容") //无“新内容”时表示获取元素的内容,有则表示将原内容修改为新内容(一函数两用)(2)元素开始标签到结束标签之间的纯文本内容//DOM 元素.textContent //jQuery $元素.text("新内容")(3)表单元素的值//DOM 元素.value //jQuery $元素.val("新值")举例:使用元素内容实现表单验证;<body> <h1>操作元素的内容和值</h1> <form action=""> 用户名:<input name="uname"> <span></span><br> 密码:<input type="password" name="upwd"> <span></span><br> <input type="submit" value="提交注册信息"> </form> <script src="js/jquery-1.11.3.js"></script> <script> //正确时,使用图片:"<img src='img/ok.png'>" //姓名错误时: "<img src='img/err.png'>用户名必须介于3~9位之间!" //密码错误时: "<img src='img/err.png'>密码必须介于6~8位之间!" //DOM 4步 // 验证用户名 //1. 查找触发事件的元素 // 触发事件的元素是文本框,文本框失去焦点时进行验证 $(":text") //2. 绑定事件处理函数 .blur(function () { var $this = $(this); //3. 查找要修改的元素 //查找当前文本框旁边的span元素 var $span = $this.next(); //4. 修改元素 // 4.1获得当前文本框的内容 var value = $this.val(); // 4.2进行验证 if (value.length >= 3 && value.length <= 9) { // 4.3修改span的内容 $span.html(`<img src='img/ok.png'>`); } else { $span.html(`<img src='img/err.png'>用户名必须介于3~9位之间!`); } }) // 验证密码 // 1.查找触发事件的元素 // 触发事件的为密码框 $(":password") // 2.绑定事件处理函数 .blur(function () { var $this = $(this); // 3.查找需要修改的元素 // 当前密码框跟前的span元素 var $span = $this.next(); // 4.修改元素 // 4.1先获取密码框的内容 var value = $this.val(); // 4.2进行验证 if (value.length >= 6 && value.length <= 8) { $span.html(`<img src='img/ok.png'>`); } else { $span.html(`<img src='img/err.png'>密码必须介于6~8位之间!`); } }) </script> </body> 2. 修改属性(1)字符串类型的 HTML 标准属性//DOM/ //旧核心DOM/ 元素.getAttribute("属性名") 元素.setAttribute("属性名","新值") //新HTML DOM 元素.属性名=新值 //jQuery $元素.attr("属性名","新值") $元素.prop("属性名","新值")举例:点击图片切换下一张;<body> <h1>操作元素的属性</h1> <img src="img/1.jpg" alt="1"> <script src="js/jquery-1.11.3.js"></script> <script> //DOM 4步 // 1. 查找触发事件的元素 // 查找img $("img") // 2. 绑定事件处理函数 .click(function () { // 3. 查找要修改的元素 // 修改img本身 var $this = $(this); // 4. 修改元素 // 4.1取出当前img元素中alt属性值转为整数 var alt = parseInt( $this.attr("alt") ); // 4.2如果属性值<4,就++;否则变回1 if (alt < 4) { alt++; } else { alt = 1; } // 4.3.3将新的alt值拼成图片路径,放入当前img的src属性中 $this.attr({ src: `img/${alt}.jpg`, alt: alt }); }) </script> </body> (2)bool 类型的 HTML 标准属性//DOM //HTML DOM 元素.属性名 //jQuery $元素.prop("属性名",新bool值)(3)自定义扩展属性//DOM //旧核心DOM: 元素.getAttribute() 元素.setAttribute() //HTML5: 元素.dataset.属性名 //jQuery $元素.attr()举例:点小图片,切换大图片;<body> <img src="img/1.jpg" data-click data-target="img/1-l.jpg" class="my-small"> <img src="img/2.jpg" data-click data-target="img/2-l.jpg" class="my-small"> <img src="img/3.jpg" data-click data-target="img/3-l.jpg" class="my-small"> <img src="img/4.jpg" data-click data-target="img/4-l.jpg" class="my-small"> <hr /> <img src="img/1-l.jpg" class="my-big"> <script src="js/jquery-1.11.3.js"></script> <script> //点击小图片,下方my-big中显示大图片 //DOM 4步 // 1. 查找触发事件的元素 // 查找所有带有data-click属性的img元素 $("[data-click]") // 2. 绑定事件处理函数 .click(function () { // 3. 查找要修改的元素 // 修改下方大图 var $big = $(".my-big"); // 4. 修改元素 // 4.1获得当前点击的img的data-click属性值保存的大图片路径 var src = $(this).attr("data-target"); // 4.2将大图路径设置给大图的src属性 $big.attr("src", src); }) </script> </body>3. 修改样式//DOM //修改内联样式 元素.style.css属性="新值" //获取完整样式 getComputedStyle(元素) //jQuery //获取css属性值、修改css属性值 $元素.css("css属性","新值") //如果.css()中没有给新值,则.css()底层自动执行getComputedStyle()操作,获取属性值 //如果.css()中给了新值,则.css()底层自动执行.style.css属性,执行修改操作批量修改一个元素的多个css属性://DOM 元素.className="class名" //只能整体替换所有class,不便于修改其中某一个class //jQuery $元素.addClass("className") //添加一个class $元素.removeClass("className") //去除一个class $元素.hasClass("className") //判断是否有某个calss $元素.toggleClass("className") //在有或没有一个class之间来回切换举例:实现双态按钮;<head lang="en"> <meta charset="UTF-8"> <title></title> <style> .btn { padding: 5px 10px; border-radius: 3px; border: 1px solid #aaa; outline: none; } .up { background: #fff; color: #333; } .down { background: #ddd; color: #fff; } </style> </head> <body> <button class="btn up">双态按钮</button> <script src="js/jquery-1.11.3.js"></script> <script> //双态按钮: 让按钮的class在up和down之间切换 //DOM 4步 //1. 查找触发事件的元素 $(".btn") //2. 绑定事件处理函数 .click(function () { //3. 查找要修改的元素 var $this = $(this); if ($this.hasClass("down")) { $this.removeClass("down") } else { $this.addClass("down") } //$(this).toggleClass("down") //等价于if else //4. 修改元素 }) </script> </body> 二、按节点间关系查找1. DOM 两种关系,六个属性(1)父子关系元素.parentElement //父元素 元素.children //所有直接子元素 元素.firstElementChild //第一个直接子元素 元素.lastElementChild //最后一个直接子元素(2)兄弟关系元素.previousElementSibling //前一个兄弟元素 元素.nextElementSibling //后一个兄弟元素2. jQuery两种关系,八个属性(1)父子关系$元素.parent() //父元素 $元素.children() //所有直接子元素 $元素.children("选择器") //只选择符合要求的个别直接子元素 $元素.find("选择器") //选择所有后代中符合要求的元素 $元素.children(":first-child") //第一个直接子元素 $元素.children(":last-child") //最后一个直接子元素(2)兄弟关系$元素.prev() //前一个兄弟 $元素.prevAll("选择器") //之前所有兄弟: $元素.next() //后一个兄弟 $元素.nextAll("选择器") //之后所有兄弟 $元素.siblings("选择器") //除当前元素之外,其余所有兄弟元素 案例:标签页效果;<head> <meta charset="UTF-8"> <style> .tabs { list-style: none; padding: 0 } .tabs a { text-decoration: none; color: #000; padding: 6px 12px; display: inline-block; } .tabs>li { float: left; border-bottom: 1px solid #000; } .tabs>.active { border: 1px solid #000; border-bottom: 0; } </style> </head> <body> <h1>使用属性选择器实现标签页头的切换</h1> <ul class="tabs"> <li class="active"> <a data-toggle="tab" href="#">十元套餐</a> </li> <li> <a data-toggle="tab" href="#">二十元套餐</a> </li> <li> <a data-toggle="tab" href="#">三十元套餐</a> </li> </ul> <script src="js/jquery-1.11.3.js"></script> <script> //DOM 4步 //1. 查找触发事件的元素 // 查找带有data-toggle属性,且属性值为tab的所有标签按钮 $("[data-toggle=tab]") //2. 绑定事件处理函数 .click(function () { //3. 查找要修改的元素 //需要修改的是 a标签的父级元素以及父级的兄弟元素 //4. 修改元素 var $this = $(this); // 4.1先为父级元素添加.active属性 $this.parent().addClass("active"); // 4.2在为父级元素的其他兄弟元素取消.active属性 $this.parent().siblings().removeClass("active"); //4.1和4.2可以合二为一(链式) //$this.parent().addClass("active").siblings().removeClass("active"); }) </script> </body> 效果如图,每点击一个套餐,就会切换到当前套餐下。
0
0
0
浏览量1318
青椒肉丝加点糖

CSS(七)元素过渡、变化、动画

一、元素动效1. 过渡 - transition  过渡为一个元素在不同状态之间切换不同的过渡效果,由过渡属性的名称、过渡需要的时间、过渡的方式、过渡的延迟时间四部分组成。注意过渡必须是在元素状态切换下进行,需要用到伪类。(1)过渡属性的名称 - transition-property  过渡样式div { transition-property: background-color; }值需要直接写需要过渡的属性名称,当过渡多个样式的时候可以写 all。(2)过渡需要的时间 - transition-durationdiv { transition-duration: 0.5s; }(3)过渡的方式 - transition-timing-function,CSS中封装了5种方式:div { transition-timing-function: linear; }(4)过渡的延迟时间 - transition-delay 延迟时间指在过渡效果开始作用之前需要等待的时间,以s或ms为单位,取值为正会延迟一段时间来响应过渡效果;取值为负会导致过渡立即开始。div { transition-delay: 1s; }(5)简化写法,格式:transition:过渡时间 延迟时间 过渡方式 过渡样式(延迟时间必须写在过渡时间以后,其他可以调换位置;最简写法为 transition:过渡时间)。div { transition: 1s 1s ease background-color; }(6)多重样式过渡,使用 transition 进行多个不同的过渡样式时,每一个不同时间的过渡样式用逗号分隔。div { transition: 1s border-radius, 1s 1s opacity; }2. 变化(1)translate( )  位移函数使用margin负值方法的元素居中必须知道子元素的宽高,而位移函数不用:.zi { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }(2)rotate( )  旋转函数,该函数默认为 Z 轴旋转,deg 单位为旋转角度,角度可以为正值或负值,旋转的中心点是元素最中心的点。div { transform: rotateZ(360deg); }(3)scale( )  缩放函数,缩放函数中的参数是以倍数为基础的,1代表当前大小,也可以写两个值,如果写一个表示x轴和y轴用同一个值。div { transform: scale(-1, -1); }(4)skew( )  倾斜扭曲函数,在 2d 变换中倾斜,可以有 X 轴和 Y 轴的倾斜角度,默认为 X 轴倾斜。div { transform: skewX(-40deg); transform: skewY(50deg); }(5)基点 - transform-origin改变元素变化时的原点,默认情况下,元素的中心原点位于 x 轴和 y 轴的 50% 处。3. 动画(1)关键帧  - @keyframescss中的@规则,通过在动画序列中定义关键帧的样式,来控制CSS动画序列中的步骤,以百分比来规定改变发生的时间,或者通过关键词"from"和"to",等价于0%和100%。创建关键帧方法如下:@keyframes move { 0% {transform: translate(0);} 100% {transform: translate(600px);} } /* 0%为开始时间 */ /* 100%为结束时间 */ /* move为帧名 */(2)动画名称  - animation-name,指定动画要使用哪一个关键帧。(3)结束时间 - animation-duration,代表一个动画周期的时长,默认值0秒,调用动画时必须写:动画名称、持续时间。(4)运动方式 - animation-timing-functiondiv { animation-timing-function: steps(8,end); }(5)延迟时间 - animation-delay,与过渡延迟时间同用。(6)结束状态 - animation-fill-mode,设置动画结束时盒子的状态,在动画运行到某个位置的时候,动画停止,元素默认会迅速回到起始位置。(7)执行顺序 - animation-direction(8)循环次数 - animation-iteration-count,其值通常为整数,默认为1,值infinite表示无限循环。(9)简写方式        格式:animation: 执行时间  延迟时间  关键帧名称  运动方式  运动次数  结束状态;        最简:最简方式 animation: 动画执行时间  执行关键帧名称;( 注意执行时间和延迟时间顺序不可调整)(10)动画停止 - animation-play-state,单独写,不可加入简写之中。/*鼠标移入ul时,暂停动画*/ .xz-roll ul:hover { animation-play-state: paused; }css 样式将对布局、字体、颜色、背景和其它文图效果实现更加精确的控制。只通过修改一个文件就改变页数不计的网页的外观和格式。 在所有浏览器和平台之间的兼容性。更少的编码、更少的页数和更快的下载速度。除了还不能全面支持我们常用的大多数浏览器之外,CSS 在实现其它承诺方面作得相当出色。CSS 在改变我们制作样式表的方法,它为大部分的网页创新奠定了基石。
0
0
0
浏览量1068
青椒肉丝加点糖

JS 高级(三)继承、多态、ES5严格模式

一、面向对象1. 继承            只要将方法定义放在构造函数中,那么每次 new 时都会执行 function,这样就会反复创建相同函数的多个副本,导致浪费内存。如果将来发现多个子对象都要使用相同的功能和属性值时,都可以用继承来解决。        父对象中的成员,子对象无需重复创建就可直接使用,就像使用自己的成员一样,这就是继承。js 中的继承都是通过原型对象实现的,原型对象就是替所有子对象集中保存共有属性值和方法的特殊父对象。当多个子对象需要使用相同的功能和属性值时,都可将相同的功能和属性值集中定义在原型对象中。        原型对象不用自己创建,在定义构造函数时,程序自动附赠我们一个空的原型对象。构造函数中都有一个自带的属性 prototype,指向自己配对的原型对象——构造函数 .prototype。new 的第二步自动让新创建的子对象,继承构造函数的原型对象。new 会自动为子对象添加_ _proto_ _ 属性,指向构造函数的原型对象。向原型对象中添加新的共有属性和方法时,只能是强行赋值:        添加新属性或方法后,用子对象访问对象的成员时,js引擎先在子对象内部查找自有的属性;如果子对象没有,则 js 引擎会自动延 _ _proto_ _ 属性去父元素查找。如果在父元素中找到了想要的属性或方法,则和访问子对象的方法一样调用。        示例: 将所有子对象共用的方法保存进构造函数里<script> // 构造函数 function Student(sname, sage) { this.sname = sname; this.sage = sage; } // 强行向student类型的原型对象(prototype)中添加一个所有子对象共用的的方法intr Student.prototype.intr = function () { console.log(`我叫${this.sname},我今年${this.sage}岁`); } // 用构造函数反复创建多个相同结构但内容不同的对象 var lilei = new Student("李雷", 45); var hmm = new Student("韩梅梅", 30); console.log(lilei); console.log(hmm); lilei.intr(); hmm.intr(); console.log(lilei.__proto__ == Student.prototype); //true说明原型对象是子元素的父级 console.log(hmm.__proto__ == Student.prototype); //true </script>自有属性和共有属性(1)获取属性值时,毫无差别,都可用: 子对象.属性名。如果 js 引擎发现要使用的属性不在子对象中,则自动延 _ _proto_ _ 属性向父对象继续查找要用属性。(2)修改属性值示例: 为所有学生添加共有的班级名属性,并修改;<script> function Student(sname, sage) { this.sname = sname; this.sage = sage; } Student.prototype.className = "初一二班"; var lilei = new Student("lilei", 11); var hmm = new Student("hmm", 12); // 修改自有属性 lilei.sname = "zhangsan"; console.log(lilei); console.log(hmm); console.log(lilei.className, hmm.className); // 一年后,两位同学一起升级(修改共有属性) // 1.错误方式 // lilei.className = "初二二班"; // 此方式不会修改原型对象中的共有属性,而会给当前子对象添加一个同名的自有属性,导致该子对象与其他子对象无法继续保持同步。 // 2.正确方式,必须修改原型对象 Student.prototype.className = "初二二班"; console.log(lilei.className, hmm.className); </script> 内置类型的原型对象        内置类型就是 ES 标准中规定的,浏览器已经实现,我们可以直接使用的类型。包括十一种String、Number、Boolean、Array、Date、RegExp、Error、Function、Object、Math(不是类型,而是一个{ }对象)、global(全局作用域对象,在浏览器中被window代替)。        每种类型一定有2部分组成:构造函数,负责创建该类型的子对象;原型对象,负责为该类型所有子对象集中保存共有的属性值和方法定义。除 Math 和 global 之外,其余也都可以通过 new 创建子对象。        想要查看该类型中有哪些 API,可以使用 -- 类型名.prototype -- 。        如果经常使用的一个功能,但是原型对象中没有提供,我们可以自定义一个函数保存到原型对象中。举例:为数组类型添加求和的方法<script> var array1 = [1, 2, 4, 5, 8, 8]; var array2 = [125, 48, 48, 478, 2584]; // 创建自定义函数 Array.prototype.sum = function () { console.log("调用自定义函数sum"); // 数组求和套路 // 1.定义变量临时保持求和的值 var sum = 0; // 2.遍历数组元素 for (i = 0; i < this.length; i++) { // 3.将遍历出的元素值累加 sum += this[i]; } // 4.返回累加结果 return sum; } // 调用sum console.log(array1.sum()); console.log(array2.sum()); </script> 原型链        原型链是由多级父对象逐级继承形成的链式结构,保存着:一个对象可用的所有属性和方法,控制着属性和方法的使用顺序,采用就近原则,先子级后父级。<script> function Student(sname, sage) { this.sname = sname; this.sage = sage; } // 向Student原型对象中添加一个toString方法 Student.prototype.toString = function () { // 此处this指将来调用这个toString()的点前的某个学生的类型的子对象. return `{sname:${this.sname},sage:${this.sage}}`; } var lilei = new Student("lilei", 12); var arr = [1, 2, 3]; var now = new Date(); console.log(lilei.toString()); console.log(arr.toString()); console.log(now.toString); </script> 2. 多态        多态指同一个函数,在不同情况下表现出不同的状态,包括重载和重写。3. 自定义继承(1)只更换一个对象的父对象,两种方法://示例:更换一个对象的父对象 <script> function Student(sname, sage) { this.sname = sname; this.sage = sage; } var lilei = new Student("李磊", 11); var hmm = new Student("韩梅梅", 12); var father = { money: 1000000000000, car: "infiniti" } // 1.只更换一个对象的父对象 // 更换hmm的继承父对象为father // hmm.__proto__ = father;//不推荐 Object.setPrototypeOf(hmm, father); //推荐 console.log(hmm.money, hmm.car); console.log(lilei.money, lilei.car); console.log(lilei); console.log(hmm); </script>(2)批量更换多个子对象的父对象,只需要更换构造函数的 prototype 属性就可以,但必须在创建子对象之前更换!//示例: 批量更换两个子对象的父对象 <script> function Student(sname, sage) { this.sname = sname; this.sage = sage; } var father = { money: 1000000000000, car: "infiniti" } // 2.批量更换多个子对象的父对象 // 必须在创建子对象之前更换构造函数的原型对象 Student.prototype = father; var lilei = new Student("李磊", 11); var hmm = new Student("韩梅梅", 12); console.log(hmm.money, hmm.car); console.log(lilei.money, lilei.car); console.log(lilei); console.log(hmm); </script> 二、ES5(ECMAScript 第5个版本)1. 严格模式        在旧的js中有很多广受诟病的缺陷,严格模式就是比旧的js运行机制要求更严格的新运行机制,今后企业中所有代码都要运行在严格模式下。启用严格模式只需在当前代码段的顶部添加:   "use strict"; 即可。严格模式有四个新规定: a:禁止给未声明过的变量赋值;旧的js中,如果强行给未声明过的变量赋值,不会报错,而是,自动在全局设置该变量,这就造成了全局污染。而严格模式中,强行给未声明过的变量赋值,会报错,这样就减少了因为写错变量名造成的全局污染!举例:给未声明的局部变量赋值<script> function send() { var gf; // 假设不小心写错了变量名 qgf = "今晚308,w84u"; //直接报错qgf is not defined console.log(`女朋友收到${gf}`); } send(); console.log(`全局中:${qgf}`); </script>未使用严格模式,打印如下,本来想给“女朋友”发送的消息,却发到了全局,但系统不报错。启用严格模式,在代码段首行添加"use strict";<script> // 启用严格模式 "use strict"; // 禁止给未声明过的变量赋值 function send() { var gf; // 假设不小心写错了变量名 qgf = "今晚308,w84u"; //直接报错qgf is not defined console.log(`女朋友收到${gf}`); } send(); console.log(`全局中:${qgf}`); </script> 打印如下,此时直接报错,便于我们发现程序中的问题并修改。 b. 静默失败升级为错误;静默失败指程序运行不成功,但是也不报错,这样极其不利于调试程序,严格模式:会将绝大部分静默失败都升级为报错。<script> // 静默失败升级为错误 var eric = { aid: 1001, sanme: "斯塔克" } // 这里将eid属性设置为只读 Object.defineProperty(eric, "eid", { writable: false }) // 试图篡改 eric.eid = 1002; console.log(eric); </script>打印如下:即使将eid设置为只读,属性值仍被修改,但不报错。 启动严格模式后打印如下: c. 普通函数调用中的 this 不再指 window,而是指 undefined,在旧 js 中普通函数调用中的 this 默认指 window,极容易造成全局污染。启用严格模式后普通函数调用中的 this 指向 undefined,不再指 window,可防止因为错误使用 this 而导致的全局污染。<script> // 启用严格模式 "use strict"; // 普通函数调用中的this不再指window,而是指undefined function Student(sname, sage) { console.log(this); this.sname = sname; //报错 Cannot set property 'sname' of undefined this.sage = sage; } var lilei = new Student("李蕾", 12); // 假设忘记写new var hmm = Student("韩梅梅", 13); console.log(lilei); console.log(hmm); console.log(window); </script> d. 禁用了 arguments.callee,arguments.callee; 是在一个函数内,获得当前函数本身的一种特殊关键字(递归)。在函数内写死当前函数名,一旦外部函数名改变,内部函数名忘记修改,则程序立刻报错造成紧耦合,所以在函数内使用 arguments.callee 代替写死的函数名。在运行时,自动获得当前函数本身(松耦合)。        而且递归重复计算量太大,效率极低,如果递归调用严重影响程序的性能时,就要用循环来代替递归。举例:分别使用递归和循环实现计算斐波那契数列第 n 个数//递归方式 <script> // 禁用了arguments.callee // 斐波那契数列 // 前两个数是都是1,从第三个数开始,每个数都是它相邻的前两个数的和 function f(n) { if (n < 3) { return 1; } else { return arguments.callee(n - 1) + arguments.callee(n - 2); } } console.log(f(10));//55 </script>//循环方式 <script> function f(n) { if (n < 3) { return 1; } else { var f1 = 1, f2 = 1, fn; for (var i = 3; i <= n; i++) { fn = f1 + f2; f1 = f2; f2 = fn; } return fn; } } console.log(f(10)); //55 </script>补充:this 4种指向; (1)obj.fun() fun中的this指 .前的obj对象(谁调用指谁); (2)new Fun() Fun中的this指new创建的新对象; (3)fun() 或 (function(){ ... })() 或 回调函数 thisz默认指windozw; (4)原型对象(prototype)中的this指将来调用这个共有函数的.前的某个子对象(谁调用指谁)。
0
0
0
浏览量2015
青椒肉丝加点糖

H5画布 canvas(一)canvas简介、绘制圆形/矩形、案例饼状图绘制

1. canvas 简介        canvas 是HTML5 提供的一种新标签 <canvas></canvas>,与 div 类似,是一个矩形的画布,它可以支持 JavaScript 在上面绘画,控制每一个像素;canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法,可以使得页面更加丰富多彩。当前 canvas 广泛应用于游戏、可视化数据(echarts)、广告等领域。2. canvas 标签介绍        canvas 其实就是一个普通的 HTML 标签,需要进行闭合,可以设置宽高、背景色属性,但宽高单位必须是 px,否则就会被忽略;一个 canvas 默认为 300*150 像素。  需要注意 canvas 元素的宽高必须使用它自带的属性进行设置,而不要用 CSS 选择器控制 canvas 的宽高,否则会造成图像拉伸,除宽高之外的其余属性则可用 CSS。如下简单案例:<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>canvas标签</title> <style> #can1 { background-color: cadetblue; border: 2px solid red; } </style> </head> <body> <!-- 设置宽高使用canvas标签的属性 --> <canvas id="can1" width="300px" height="150px"></canvas> </body> </html>效果如下:3. canvas 上下文 Context   Context 是 canvas 的上下文,也就是绘制环境,它是所有绘制操作 api 的入口或者集合;canvas 本身是无法绘制任何内容的,需要使用 JavaScript 进行操作。而 Context 正是 JavaScript 操作 canvas 的接口。获取上下文分为两步:首先获取 canvas 标签,然后再获取该标签的上下文;<script> // 1.DOM操作获取canvas标签 var canvas = document.getElementById('can1'); // 2.获取canvas的上下文(2d渲染) var ctx = canvas.getContext('2d'); </script>获取 canvas 上下文之后,就可以在画布上进行图形绘制了;上下文 Context 相关属性如下:(ctx 是博主定义的获取到的上下文 Context 的变量名,可以随意更换,以下介绍都用ctx)ctx.moveTo(x,y);将画笔移动到坐标(x,y)位置ctx.lineTo(x,y);从当前位置绘制直线到坐标(x,y)位置ctx.closePath();关闭路径,闭合线条ctx.lineWidth;线宽ctx.strokeStyle;描边颜色,必须用于描边之前ctx.stroke();渲染直线,相当于描边ctx.fillStyle;填充颜色,必须用于填充之前ctx.fill();填充,默认为黑色接下来我们结合这些属性绘制一个简单的正方形:<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>canvas标签</title> <style> #can1 { background-color: rgb(204, 216, 216); border: 2px solid red; } </style> </head> <body> <!-- 设置宽高使用canvas标签的属性 --> <canvas id="can1" width="600px" height="500px"></canvas> </body> <script> // DOM操作获取canvas标签 var canvas = document.getElementById('can1'); // 获取canvas的上下文(2d渲染) var ctx = canvas.getContext('2d'); // 绘制长方形 ctx.moveTo(100, 100); //将画笔移动到坐标 100 100 ctx.lineTo(200, 100); //从画笔位置绘制直线到坐标 200 100 ctx.lineTo(200, 200); //从当前位置绘制直线到 200 200 ctx.lineTo(100, 200); //.从当前位置... ctx.closePath(); //闭合线条 ctx.lineWidth = 6; //线宽 ctx.strokeStyle = 'red'; //描边颜色 ctx.stroke(); //渲染直线(描边) ctx.fillStyle = 'blue'; //填充颜色 ctx.fill(); //填充 </script> </html>效果如下:4. 案例:在 canvas 画布中绘制表格<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>案例:绘制表格</title> <style></style> </head> <body> <div> <canvas id="table"></canvas> </div> </body> <script> (function () { var canvas = document.getElementById('table'); //获取canvas标签 var ctx = canvas.getContext('2d'); //获取上下文 //设置画布宽高、边框(边框也可使用CSS选择器来设定) canvas.width = 600; canvas.height = 400; canvas.style.border = '2px solid #000'; //设置上下文样式 ctx.lineWidth = .5; ctx.strokeStyle = '#999'; //绘制表格 var rect_hei = 20; //定义每一行高20px var rect_wit = 40; //定义每一列宽40px for (var i = 0; i < canvas.width / rect_hei; i++) { //循环绘制 //绘制横线 ctx.moveTo(0, i * rect_hei); //从x轴为0的位置开始,每隔一个行高便绘制横线 ctx.lineTo(canvas.width, i * rect_hei); ctx.stroke(); //绘制竖线 ctx.moveTo(i * rect_wit, 0); //从y轴为0的位置开始,每隔一个列宽便绘制竖线 ctx.lineTo(i * rect_wit, canvas.height); ctx.stroke(); } }()) </script> </html>效果如下:5. canvas 的 beginPath 状态      需要知道,在 canvas 画布中绘制图形是基于状态的,意思就是说如果前面已经设置了描边颜色属性 strokeStyle 为某个颜色,那么在这之后的绘制当中,所有线条都会是这个颜色;如果再次设置描边颜色,则所有线条都会成为最新设置的颜色,前面设置的都被覆盖,无法做到颜色不一。如下:而这个时候,为了能够绘制出不同颜色的线条,就需要使用到 beginPath 开启新状态;ctx.beginPath();开启新状态的绘图,前面的设置不会被覆盖;新状态可以继承之前状态的样式,但是在新状态中设置的样式就只能作用在新状态当中。如下案例:6. 绘制矩形 rect   如果只是按照步骤:起点 --> 画线 --> 描边 一步一步的绘制一个矩形的话,就太麻烦了,canvas 也提供了一种快速绘制矩形的方法 rect,并且提供了各种属性。语法如下:ctx.rect(x, y, width, height);x, y为矩形左上角坐标, width 和 height 以像素 px 为单位,该语法只规定了矩形的路径,没有填充和描边。ctx.strokeRect(x, y, width, height);描边矩形,结合绘制与描边。ctx.fillRect(x, y, width, height);填充矩形,结合绘制与填充ctx.clearRect(x, y, width, height);清除矩形,相当于橡皮擦,在该矩形范围内的图像都会被擦除。我们使用 rect 语法绘制一个矩形,只需一句代码即可:<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>绘制矩形</title> <style></style> </head> <body> <div> <canvas id="table"></canvas> </div> </body> <script> var canvas = document.getElementById('table'); //获取canvas标签 var ctx = canvas.getContext('2d'); //获取上下文 //设置画布宽高、边框(边框也可使用CSS选择器来设定) canvas.width = 600; canvas.height = 400; canvas.style.border = '2px solid #000'; //快速绘制矩形 ctx.rect(100, 100, 50, 50); ctx.stroke(); //描边矩形 ctx.strokeRect(200, 100, 50, 50); //填充矩形 ctx.fillRect(300, 100, 50, 50); </script> </html>效果如下:7. 绘制圆形 arcctx.arc(x,y,r,sAngle,eAngle,counterclockwise);x、y 为圆心点坐标;r 半径;sAngle 开始角度,圆心到最右边点为 0 度,顺时针方向依次增大;eAngle 结束角度,注意用的是弧度 Π(180°);counterclockwise:是否是逆时针,true 是逆时针,false 顺时针。接下来,我们使用 arc 绘制一个圆弧,效果如下:(提示:弧度与角度的转换公式,角度 = 度数 * Math.PI / 180)8. 案例:根据一组数据绘制饼状图<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>绘制饼状图</title> <style></style> </head> <body> <div> <canvas id="table"></canvas> </div> </body> <script> var canvas = document.getElementById('table'); //获取canvas标签 var ctx = canvas.getContext('2d'); //获取上下文 //设置画布宽高、边框(边框也可使用CSS选择器来设定) canvas.width = 600; canvas.height = 400; canvas.style.border = '2px solid #000'; //定义饼状图数据 var data = [{ 'value': 0.2, 'color': '#149985', 'title': '城市A' }, { 'value': 0.3, 'color': 'red', 'title': '城市B' }, { 'value': 0.4, 'color': 'blue', 'title': '城市C' }, { 'value': 0.1, 'color': '#999999', 'title': '城市D' }, ] //绘制饼状图 var tempAngle = -90; //从-90°开始绘制 for (var i = 0; i < data.length; i++) { ctx.beginPath(); //每一次循环都绘制不同的扇区,所以都要开启新状态 ctx.moveTo(200, 200); //每一次都回到圆心点开始绘制 var angle = data[i].value * 360; //每一个扇区的角度 ctx.fillStyle = data[i].color; //颜色填充按照数据遍历 var startAngle = tempAngle * Math.PI / 180; //起始角度 var endAngle = (tempAngle + angle) * Math.PI / 180; //每一次的结束角度=起始角度+扇区角度 ctx.arc(200, 200, 100, startAngle, endAngle); tempAngle = tempAngle + angle; //每次绘制完一次扇区起始角度为原角度加该扇区角度 ctx.fill(); } </script> </html>案例效果如下:饼状图文字的绘制等参见下期:H5画布 canvas 入门到精通 _ 第二部分小结:canvas 绘制基本步骤获得上下文:canvas.getContext('2d')开始新状态绘制:ctx.beginPath()画笔起始点:ctx.moveTo(x, y)绘制线:ctx.lineTo(x, y)闭合路径:ctx.closePath()描边:ctx.stroke()
0
0
0
浏览量1314
青椒肉丝加点糖

HTML(一)html书写规则、基础元素、功能元素

   HTML全称hyper text markup language,超文本标记语言。是构建页面的标记,用于承载网站的内容。一、HTML语句规则1. 文档结构2. 标签书写(1)标签名使用小写;(2)双标签成对出现;(3)标签在 html5 规范中可以省略`/`。3. 属性书写        标记和属性用空格隔开,属性与属性值用`=`连接,属性值写在双引号内,等号两侧不空格。属性名用小写,一个标记可以没有属性也可以有多个不同属性,属性之间不分先后顺序。4. 文件加载        浏览器有专门的 html 解析器,浏览器是自上而下解析的,顺序加载整个页面的标签。5. 标签嵌套        块元素可以包含内联元素或某些块元素,但内联元素却不能包含块元素,它只能包含其它的内联元素。有几个特殊的块级元素,内部只能包含内联元素,不能再包含块级元素如 h1-h6 标题。6. HTML常用字符实体二、HTML基础元素1. 标题标签(h1-h6)该标签用于书写标题,属于块级元素,在浏览器中自占一行。共有六个:<h1>⼀级标题</h1><h2>⼆级标题</h2><h3>三级标题</h3><h4>四级标题</h4><h5>五级标题</h5><h6>六级标题</h6>2. 段落标签(<p> </p>)用于书写段落或大段文字,属于块级元素,在浏览器中自占一行。3. 换行标签(<br />)该标签为单标签,属于块级元素,自占一行。多用于段落中的换行,但一般不用于布局。4. 预格式化标签(<pre> </pre>)  定义预格式化的文本,浏览器会完整保留源文件中的格式,包括各种空格、缩进以及其他特殊格式,属于块级元素,在浏览器中自占一行的标签。 预格式化标签可以在在页面中显示标签,则需要搭配实体符号解决。5. 格式化⽂本标记<b>粗体</b><i>斜体</i><u>下划线</u><del>删除线 </del><sup>上标</sup> <sub>下标</sub><strong>着重⽂字,与 b 效果相同</strong><em>加重语⽓,与 i 效果相同</em><mark>⾼亮显示⽂本</mark> 6. 按钮标签(<button> </button>)       普通的按钮标签,不具备任何功能,可以自主赋予功能具有自己的样式,可以自定义修改,按钮标签是特殊的内联元素,可以设置宽度高度,不自占一行。7. 分区元素    div 标签:为块级元素,自身没有任何样式。经常作为容器和分区域的包裹标签使用,在布局中应用广泛。     span 标签:为内联元素,自身没有任何样式,常作为容器使用,用于包裹特殊的文字和图标。8. 全局属性      全局属性是所有 HTML 元素共有的属性。它们可以用于所有元素,即使属性可能对某些元素不起作用。(1)style属性:含要应用于元素的样式声明,可以给元素指定样式可以设置多个样式,每个属性值用分号隔开。需要注意的是,该属主要用于快速样式化,用于测试目的。(2)id属性:唯一标识符,在该页面上一个标签只能有一个不重复的 id 名,它具有唯一性。id属性的值不能是数字开头,不建议写中文。(3)class属性:可以将元素进行分类后给予相同的样式,减少了代码的书写量,该页面上可以有多个元素拥有此类名,一个元素也可以有多个类。class选择器名称不能是数字开头,不建议写中文,可以是多个类名用空格隔开。(4)data-*⾃定义属性:data-*是自定义数据属性,可以通过 JavaScript 与 HTML 之间进行专有数据的交换。data-*`这里的*可以替换为自定义的有意义的字母或单词,如:data-buy。三、HTML功能元素1. URL  统一资源定位符就是我们俗称的“网址”,可以用来标识网络上的任何资源,也可以叫做路径。路径分为三种:绝对路径:完整的描述文件位置的路径。例如 http://www.zyncode.net/index.html相对路径:相对路径就是相对于当前⽂件的路径,相对路径不带有盘符。例如 ./logo.gif根相对路径: 永远都是从 web 站点所在的根⽬录处开始查找。2. 超链接        <a></a>标签,定义超链接  href 属性:表示超文本引用,用来建立当前元素和文档之间的链接。  锚URL:href="#top",那么点击时就会到当前页面中 id="top" 的这个锚点,实现当前页面的所谓跳转。   空链接:<a href="#"></a>,#是标签内置的一个方法,代表 top 的作用。点击后网页后返回到页面顶端。     target 属性:规定在何处打开链接文档。有两个属性:_blank,浏览器总在一个新打开、未命名的窗口中载入目标文档;_parent,使文档载入父窗口或者包含来超链接引用的框架的框架集。3. 图像        <img src=""/>4. 多媒体        <video src="视频路径"></video>controls 属性提供播放、暂停和音量的控件;loop 属性提供循环播放;width 属性可以直接控制多媒体文件的宽度。
0
0
0
浏览量1920
青椒肉丝加点糖

jQuery(一)jQuery概述、使用方式、原理、查找元素

一、认识jQuery        jQuery 的核心特性是具有独特的链式语法和短小清晰的多功能接口;具有高效灵活的 css 选择器,并且可对 css 选择器进行扩展;拥有便捷的插件扩展机制和丰富的插件,且 jQuery 兼容各种主流浏览器。         jQuery 依旧执行 DOM 的增、删、改、查、事件绑定操作,可以说 jQuery 是 DOM 的延续;jQuery 对 DOM 操作的每一步都进行了简化,是用函数来解决一切问题(jQuery就是函数库)。        但是 jQuery只有PC端,没有移动端,而且只对 DOM 操作的每一步进行了简化,没有减少步骤,所以用的会越来越少。二、jQuery的使用        到官网jQuery进行下载即可,下载版本后引入网页。1. 将 jQuery 引入网页的方法(1)将 jquery.js 文件下载到项目本地文件夹,用相对路径引入<script src="js/jquery-1.11.3.js">(2)引入 CDN 网络中的 jquery.js 文件         CDN 网络可在全球范围共享一个文件;任意地区的一个客户端想用 CDN 网络中的文件时,CDN 网络都会从距离这个客户端网络最优的服务器下载资源给客户端。<script src="官网提供的CDN网址"> //eg:微软提供的cdn网址: <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.3.js">举例:对比 DOM 与 jQuery 写法;三、jQuery原理1. 引入 jquery.js 文件后,会在内存中新增一种类型,包括:(1)构造函数:创建该类型的子对象;(2)原型对象:集中保管该类型所有子对象共用的方法。2. 使用 jQuery 函数库中的函数时,需要先创建 jQuery 类型的子对象//标准写法 var jq子对象=new jQuery(选择器); //简写 var jq子对象=jQuery(选择器) var jq子对象=$(选择器) //$相当于new jQuery 1.查找DOM元素 2.创建jQuery对象         只有 jQuery 子对象才能访问 jQuery 原型对象中的简化版共有方法。原生的 DOM 元素对象无权使用 jQuery 原型对象中的简化版函数。3.  jQuery 中事件处理函数里的 this        .click 会翻译为 .οnclick=function(){ ... },再执行,所以 .click() 中的 this,其实还是 .onclick 里的 this。与 DOM 中的 this 完全一样,都指向正在点击的当前原生 DOM 元素对象本身;jquery 中所有事件处理函数中的this都必须用 $() 包裹起来(包装),形成一个 jQuery 子对象,才可以使用 jQuery 函数库中的函数。四、 jQuery API三大特点1.自带for循环遍历        只对 jQuery 查找结果对象调用一次简化版函数,就可以自动遍历查找结果中每个 DOM 元素,自动为每个 DOM 元素应用多用的 DOM 操作2.一个函数两用        和修改相关的函数,都既能用于修改新值,又能用于获取旧值;        调用函数时,没有传新值参数,函数默认执行获取旧值操作,        调用函数时,传了新值参数,函数自动改为执行修改为新值操作。举例:有多个按钮,记录每个按钮的单击次数;<body> <h1>jQueryAPI特点</h1> <button id="btn1">click me(0)</button> <button id="btn2">click me(0)</button> <button id="btn3">click me(0)</button> <script src="js/jquery-1.11.3.js"></script> <script> //为三个按钮绑定单击事件,记录单击次数 //DOM 4步 //1. 查找触发事件的元素 var $btn = $("button"); //2. 绑定事件处理函数 $btn.click(function () { //3. 查找要修改的元素:本例中改当前按钮,所以用this var $this = $(this); //4. 修改元素 var n = parseInt( $this.html().slice(9, -1) ); n++; $this.html(`click me(${n})`) }); </script> </body> 五、查找元素        jQuery 主要通过选择器的方式查找元素,除了原始 CSS 选择器之外,还添加了额外 jQuery 专属的选择器。1. 子元素过滤选择器(css选择器)举例:使用子元素过滤选择器选择指定元素;<body> <h3>子元素过滤选择器.</h3> <ul> <li>child1-basic0</li> <li>child2-basic1</li> <li>child3-basic2</li> </ul> <ul> <li>child1-basic3</li> <li>child2-basic4</li> <li>child3-basic5</li> </ul> <ul> <li>child1-basic6</li> </ul> <script src="js/jquery-1.11.3.js"></script> <script> //查找每个ul中第一个li,让其字体颜色变为红色 $("ul>li:first-child").css("color", "red"); //查找每个ul中最后一个li,让其边框变为绿色 $("ul>li:last-child").css("border", "1px solid green"); //查找每个ul中处于偶数位置的,让其背景变为黄色 $("ul>li:nth-child(2n)").css("background", "yellow"); //查找每个ul中第2个li,添加蓝色阴影 $("ul>li:nth-child(2)").css("box-shadow", "0 0 10px blue"); //查找作为ul下唯一子元素的li,设置20px内边距 $("ul>li:only-child").css("padding", "20px"); </script> </body>2. 基本过滤选择器(jQuery专属)        先将所有符合要求的元素集中保存到一个大的集合中从0开始统一编号,按元素在集合中的统一编号来选择指定的元素。举例:使用基本过滤选择器选择指定元素;<body> <h3>基本过滤选择器.</h3> <ul> <li>child1-basic0</li> <li>child2-basic1</li> <li>child3-basic2</li> </ul> <ul> <li>child1-basic3</li> <li>child2-basic4</li> <li>child3-basic5</li> </ul> <ul> <li>child1-basic6</li> </ul> <script src="js/jquery-1.11.3.js"></script> <script> //查找第一个li,字体变化红色 $("li:first").css("color", "red"); //查找最后一个li,边框变为绿色 $("li:last").css("border", "1px solid green"); //查找处于(正常人眼)偶数位置的li,背景变为黄色 $("li:odd").css("background", "yellow"); //查找第2个li,添加蓝色阴影 $("li:eq(2)").css("box-shadow", "0 0 10px blue"); </script> </body>3. 内容过滤器(jQuery专属)         根据元素的内容不同来选择元素。举例:使用内容过滤选择器选择指定元素;<body> <div class="container"> <h1>内容过滤选择器</h1> <button>提交订单</button> <button>Submit注册信息</button> <button>马上提交</button> <button>清空重填</button> <hr /> <div class="alert"></div> <div class="alert"> <span class="close">×</span> </div> </div> <script src="js/jquery-1.11.3.js"></script> <script> //选择包含"提交"二字的按钮,变为绿色按钮 $("button:contains(提交)").css("background-color", "green"); //选中包含.close按钮的.alert元素,让它们变为红色的警告框 $(".alert:has(.close)").css("background-color", "red"); //选中不包含.close按钮的.alert元素,让它们变为绿色的警告框 $(".alert:not(:has(.close))").css("background-color", "green"); //选择内容为空的.alert元素,添加红色阴影 $(".alert:empty").css("box-shadow", "0 0 10px red"); //选择内容不为空的.alert元素,添加绿色阴影 $(".alert:parent").css("box-shadow", "0 0 10px green"); </script>4. 可见性过滤(jQuery专属)        根据元素是否可见来选择元素;举例:使用 :hidden 选择不可见的元素;<body> <div class="container"> <h1>可见性选择器</h1> <div id="d1" style="display: none">lorem</div> <div id="d2" style="visibility: hidden">lorem</div> <div id="d3" style="opacity: 0">lorem</div> <input id="d4" type="hidden" name="aa" value="bb" /> </div> <script src="js/jquery-1.11.3.js"></script> <script> console.log($('div.container>:hidden')) </script> </body>5. 表单元素过滤选择器(jQuery专属)        根据表单元素的类别不同来选择不同的表单元素。举例:点同意时启用元素,不同意则禁用元素;<body> <form> 用户名:<input disabled></br> 密码:<input type="password" disabled></br> <input type="checkbox">我同意本站的使用条款<br> <input type="submit" value="提交注册信息" disabled /> </form> <script src="js/jquery-1.11.3.js"></script> <script> //DOM 4步 //1. 查找触发事件的元素 $(":checkbox") //2. 绑定事件处理函数 .click(function () { //3. 查找要修改的元素 var $others = $(":input:not(:checkbox)") //4. 修改元素 //如果当前checkbox是选中的 if (this.checked == true) { // 则启用其他元素 $others.prop("disabled", false); } else { // 否则禁用其他元素 $others.prop("disabled", true); } }) </script> </body>
0
0
0
浏览量95
青椒肉丝加点糖

JS 高级(二)闭包、封装

一、闭包        全局变量和局部变量在使用的过程中都各有优点,但它们也都有着自己的不足之处。全局变量的好处是可以被重用,但是极易被污染(注意一般公司中禁止使用一切形式的全局变量),局部变量虽不会被污染,但它无法重用。        为了解决此缺陷,要给一个函数定义一个专属的且可重用的变量,只有函数自己可用,其他函数不可用时,就用到了闭包!        闭包是既重用变量,又保护变量不被污染的一种编程方法,外层函数调用后,外层函数的作用域对象,被内层函数引用着,无法释放,就形成了闭包对象。闭包的使用分为三步:(1)用外层函数包裹要保护的变量和使用变量的内层函数 (2)在外层函数内部,返回内层函数对象。 (3)调用外层函数,用变量接住返回的内层函数对象。<script> // 1.用外层函数包裹要保护的变量和内层函数 function mother() { var total = 1000; // 2.外层函数返回内层函数对象 return function (money) { total -= money; console.log(`用了${money}元,还剩${total}元`); } } // 3.调用外层函数,用变量接住返回的内层函数 var pay = mother(); pay(100);//剩900 // 此处total的值不会干扰mother函数中定义的值 total = 0; pay(100);//剩800 pay(100);//剩700 </script>        然而,闭包也存在一定的不足,闭包返回的内存函数,比普通函数多占用一块内存空间(外层函数的函数作用域对象);所以,如果一个闭包不打算再使用了,就应该及时释放它。        保存内层函数的变量=null,这样就释放了内层函数对象,同时也释放了外层函数的作用域对象。二、面向对象        程序中将来会保存大量的数据。而大量数据如果零散的随意管理,极容易出错!而且用着不方便。所以在今后程序中,都是用面向对象的方式来管理大量数据的。程序中会将描述一个事物的多个属性和功能集中保存在一个对象结构中,再起一个名字。        面向对象三大特点:封装、继承、多态。1. 封装        封装是指创建一个对象,集中保存现实其中一个事物的属性和功能,极其便于大量数据的管理维护。封装有3种方式:(1){ },创建一个对象时常用,格式如下var 对象名={ 属性名: 属性值, ... : ... , 方法名: function(){ ... } }        访问对象中的属性或方法时,用--对象.属性名--或--对象.方法名()--即可。但是直接用{ }进行封装时,在对象自己的方法内,想使用对象自己的另一个属性名时,会报错!说xxx属性名未定义,解决此问题可用两种方式:        a:写死对象名.属性名,但是一旦对象名发生变化,而对象内写死的部分对象名,都会报错!故此方式不推荐。        b:今后,对象中的方法中,只要想使用当前对象自己的属性或其他方法时,都用加this。this是每个函数内自带的,不用创建,直接使用专门指向正在调用当前函数。<script> var lilei = { sname: "Li Lei", sage: 11, intr: function () { // ----------此处的this指代.前面的对象---------- console.log(`I am ${this.sname},I am ${this.sage}岁`); } } console.log(lilei.sage); lilei.intr(); lilei.sage++; console.log(lilei.sage); lilei.intr(); </script>(2)new,格式如下var 对象名=new Object();        提示:function == new Function()        强行给空对象中添加新属性和新方法,-- 对象名.新属性=属性值; --、-- 对象名.新方法=function(){ ... this.属性名 ... } --。可以看出,js 中所有对象底层都是关联数组。        在访问成员时,标准写法为-- 对象名/数组名["成员名"] --,简写为-- 对象名/数组名.成员名 --;如果成员名是数字时,只能用-- 对象名/数组名[数字] --, 如果成员名是变量时,只能用-- 对象名/数组名[变量] --,不要加引号。        需要注意:强行给不存在的位置赋值,不但不会报错,而且还会自动添加该属性;强行访问不存在的位置的值,都不会报错,而是返回undefined。<script> var lilei = {}; lilei["sname"] = "lilei"; lilei.sage = 11; console.log(lilei); console.log(lilei.className); //undefined 强行访问不存在的位置的值,都不会报错,而是返回undefined for (var 属性名key in lilei) { console.log(`属性名:${属性名key},属性值:${属性名key}`); } var lilei = []; // js中所有对象底层都是关联数组 lilei.sname = "Lilei"; lilei["sage"] = 11; console.log(lilei); console.log(lilei["className"]); //undefined for (var 属性名key in lilei) { console.log(`属性名:${属性名key},属性值:${属性名key}`); } </script> 举例: 克隆一个对象<script> var liang = { sname: "久胜战神", sage: 1000, sex: "男" } // 进行克隆 function clone(old) { // 1.先创建一个空对象等着 var now = {}; // 2.遍历元对象中的属性名 for (var oldlist in old) { // 3.获取原对象中原属性值,再添加同名属性 var oldvalue = old[oldlist]; now[oldlist] = oldvalue; } return now; } var liang2 = clone(liang); console.log(liang2); console.log(liang2 == liang); </script> (3)用构造函数        用 { } 一次只能创建一个对象。如果想创建多个相同结构的对象时,代码就会很多重复,这样极其不便于将来的维护。当想反复创建多个相同结构,只是内容不同的对象时,都用构造函数。定义构造函数:function 类型名(形参1, 形参2, ...){ //将来要加入到新对象中的规定的属性 this.属性名=形参1; this. xxx = xxx; this.方法名=function(){ ... this.属性名 ... } }用构造函数反复创建多个相同结构的对象:var 对象名=new 类型名(实参值1, 实参值2, ...)举例:定义构造函数规定学生类型对象的统一结构<script> // 定义构造函数 // ---------此处this指代新对象--------- function Student(sname, sage) { this.sname = sname; this.sage = sage; this.intr = function () { console.log(`我叫${this.sname},我今年${this.sage}岁`); } } // 用构造函数反复创建多个相同结构但内容不同的对象 var lilei = new Student("李雷", 45); var hmm = new Student("韩梅梅", 30); console.log(lilei); lilei.intr(); console.log(hmm); hmm.intr(); </script>
0
0
0
浏览量600
青椒肉丝加点糖

jQuery(四)动画、类数组对象操作、添加自定义函数、封装自定义插件

一、动画1. 简单动画举例:<body> <h1>jQuery动画函数——显示隐藏动画</h1> <button id="btn1">显示/隐藏div</button> <div id="target"> <p><span>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</span></p> </div> <script src="js/jquery-1.11.3.js"></script> <script> //点按钮,执行简单动画效果 $("#btn1").click(function () { $("#target").fadeToggle(); }) </script> </body>举例:显示隐藏部分品牌;<body> <ul id="list"> <li>0尼康(234)</li> <li>1佳能(22)</li> <li>2索尼(932)</li> <li>3宾得(11)</li> <li>4爱国者(3234)</li> <li>5欧巴(32)</li> <li>6海鸥(2334)</li> <li>7卡西欧(334)</li> <li>8三星(834)</li> <li>9松下(234)</li> <li>10其它品牌(2343)</li> </ul> <button data-toggle="brandlist">收起</button> <script src="js/jquery-1.11.3.js"></script> <script> //DOM 4步 //1. 查找触发事件的元素 // 点击按钮触发事件 $("button") //2. 绑定事件处理函数 .click(function () { //3. 查找要修改的元素 $("li:gt(4):not(:last-child)").toggle() //4. 修改元素 var $this = $(this) if ($this.html() === "收起") { $this.html("更多") } else { $this.html("收起") } }) </script> </body>2. 万能动画        能对多种 css 属性应用动画效果,但只支持单个数值的 css 属性,不支持颜色过渡和 css3 变换。//启动动画 $元素.animate({ css属性名: 目标值 },持续时间ms) //停止动画 $元素.stop()举例:<body> <h1>animate</h1> <button id="btn1">启动动画</button> <div id="d1">abcd</div> <script src="js/jquery-1.11.3.js"></script> <script> //点按钮,对任意一个css属性,应用动画效果 $("#btn1").click(function () { $("#d1").animate({ top: 500, left: 300, width: 500, height: 300, borderRadius: 150 }, 2000) }) </script> </body>3. 排队和并发(1)排队:多个 css 属性先后依次变化;同一个元素,先后调用多个 animate 时,多个 animate 中的 css 属性会排队变化。(2)并发:多个 css 属性同时变化,放在一个 animate 中的多个 css 属性默认同时变化。4. 选择器:animated //专门匹配正在播放animate动画5. 停止动画$元素.stop() //默认停止当前一个animate动画,动画队列中后续animate继续执行 $元素.stop(true) //既停止当前animate,又清空后续动画队列6. 动画播放后,自动执行        animate()还有第三个实参值——回调函数,凡是放在animate()中第三回调函数参数中的代码,只能在动画结束后自动执行。格式如下:$元素.animate( { css属性: 目标值 }, 动画持续时间, function(){ ... } //第三回调函数 );举例:点星星,播放动画;<body> <img id="s1" src="imgs/star.png"><br /> <img id="s2" src="imgs/star.png"><br /> <img id="s3" src="imgs/star.png"><br /> <img id="s4" src="imgs/star.png"><br /> <script src="js/jquery-1.11.3.js"></script> <script> //s1在屏幕左上角的小星星, 点击后从左移动到屏幕右边 $("#s1").click(function () { var $this = $(this) // 如果动画正在执行,则让他停止 if ($this.is(":animated")) { $this.stop() // 否则执行 } else { $(this).animate({ left: 400 }) } }); //s2在屏幕左上角的小星星,点击后从左移动到屏幕右边,再移动到下边——走直角 $("#s2").click(function () { var $this = $(this) if ($this.is(":animated")) { $this.stop(true); } else { $(this).animate({ left: 400 }).animate({ top: 400 }) } }) //s3在屏幕左上角的小星星,点击后从左上角移动到屏幕右下边,走斜线 $("#s3").click(function () { $(this).animate({ left: 400, top: 400 }) }) //s4点击小星星,变大、变淡.... 直至消失 $("#s4").click(function () { alert("123456"); $(this).animate({ width: 175, opacity: 0 }, 5000, function () { alert(`我是第三回调函数中的代码,最后执行`); } ) }) </script> </body>二、类数组对象操作1. 遍历//js数组 arr.forEach(function(当前元素, 当前下标, 当前数组){ }) //jQuery $jQuery查找结果.each(function(当前下标, 当前DOM元素){ })举例:遍历找到的每个元素,并执行相关操作;<body> <ul id="list"> <li>98</li> <li>85</li> <li>33</li> <li>99</li> <li>52</li> </ul> <script src="js/jquery-1.11.3.js"></script> <script> //请给每个不足60分的成绩+10分,并将超过90分的成绩用绿色背景标识出来 $("ul>li").each(function (i, li) { var $li = $(li); // 获取当前元素的内容 var n = parseInt($li.html()); if (n < 60) { $li.html(n + 10) } else if (n >= 90) { $li.css("background-color", "green") } }) </script> </body>2. 查找//js数组 var i=arr.indexOf(要找的元素值); //在数组arr中查找"要找的元素值"出现的下标位置i,如果没找到,返回-1 //jQuery var i=$jq查找结果.index(要找的DOM元素)举例:五星评价;<body> <h3>请打分</h3> <ul class="score"> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> <script src="js/jquery-1.11.3.js"></script> <script> //获得当前单击的li在所有li中的位置i,i及其执行的都变为红色,i之后的都变为白色 //DOM 4步 //1. 查找触发事件的元素 $("ul") //2. 绑定事件处理函数 .click(function (e) { //e.target代替this var $tar = $(e.target) //只有点在li上才能触发事件 if ($tar.is("li")) { var i = $("ul>li").index($tar); $(`ul>li:lt(${i+1})`) .css("background-color", "yellow"); //让>i位置的所有li背景变为白色 $(`ul>li:gt(${i})`) .css("background-color", "#fff"); } }) //3. 查找要修改的元素 //4. 修改元素 </script> </body>三、添加自定义函数        如果经常使用的一个功能,jquery 中没有提供,就可以自定义函数加入到 jquery。格式://向jquery原型对象中添加一个自定义函数 jQuery.prototype.自定义函数=function(){ } //使用自定义函数 $查找结果.自定义函数()举例:封装自定义函数,对找到的所有元素内容求和;<body> <ul> <li>85</li> <li>91</li> <li>73</li> <li>59</li> </ul> <script src="js/jquery-1.11.3.js"></script> <script> //假设在项目中经常需要对找到的所有元素求和 // 自定义函数 jQuery.prototype.sum = function () { // 定义初始化值 var result = 0; // 遍历数组中的元素值 for (var i = 0; i < this.length; i++) { // 将当前元素累加到初始化值上 result += parseInt(this[i].innerHTML); } return result; } // 调用自定义函数 console.log($("ul>li").sum()); </script> </body>四、封装自定义插件        自定义插件是页面中一块可反复使用的独立的功能区域,只要页面中一块独立的功能区域,可能被反复使用时,都要封装为插件,然后再反复使用插件。 jQuery 官方插件库 jqueryui,在 jQueryui官网 下载即可;下载后引入插件库的文件:<link rel="stylesheet" href="css/jquery-ui.css"> //1 <script src="js/jquery-1.11.3.js"> //2 <script src="js/jquery-ui.js"> //3 //注意2、3顺序不可颠倒插件的使用:        a. 按照插件要求,自行编写 HTML 内容和结构,不要加任何 class;        b. 用$("选择器")查找插件的父元素,对插件父元素调用 jquery ui 提供的专门的插件函数。举例:用 jquery ui 快速生成手风琴;<head> <title> new document </title> <meta charset="utf-8"> <link rel="stylesheet" href="css/jquery-ui.css"> <script src="js/jquery-1.11.3.js"></script> <script src="js/jquery-ui.js"></script> </head> <body> <h1>jQueryUI:Widgets —— Accordion</h1> <div id="my"> <div>《西游记》简介</div> <div>一个和尚和四个动物的故事</div> <div>《水浒传》简介</div> <div>105个男人和三个女人的故事</div> <div>《红楼梦》简介</div> <div>一个男人和一群女人的故事</div> </div> <script> // 调用accordion $("#my").accordion(); </script> </body>除了使用 jQuery 的官方插件库,我们也可以自定义插件:        a. 将原页面中插件相关的 css 代码提取到一个独立的 css 文件中保存;        b. 在独立的js中,向 jQuery 的原型对象中添加一个自定义的插件函数;jQuery.prototype.自定义插件函数=function(){ }自定义之后的调用与 jQuery ui 是一致的。举例如下:补充:this 7种(1)obj.fun()  fun中的this指 .前的obj对象(谁调用指谁);(2)new Fun()  Fun中的this指new创建的新对象;(3)fun() 或 (function(){ ... })() 或 回调函数 thisz默认指windozw;(4)原型对象(prototype)中的this指将来调用这个共有函数的.前的某个子对象(谁调用指谁);(5)访问器属性中的this指代访问器属性所在的当前对象;(6)DOM和jq中事件处理函数中的this指正在触发事件的当前DOM元素对象;(7)在jQuery自定义函数中:jQuery.prototype.共有方法=function(){ //this指将来调用这个共有方法的.前的$(...)jq对象。 }
0
0
0
浏览量416
青椒肉丝加点糖

jQuery(一)jQuery概述、使用方式、原理、查找元素

   jQuery 是一个快速、简洁的 JavaScript 框架,jQuery 设计的宗旨是 “write Less,Do More”,即倡导写更少的代码,做更多的事情。它封装 JavaScript 常用的功能代码,提供一种简便的 JavaScript 设计模式,优化 HTML 文档操作、事件处理、动画设计和 Ajax 交互。一、认识jQueryjQuery 的核心特性是具有独特的链式语法和短小清晰的多功能接口;具有高效灵活的 css 选择器,并且可对 css 选择器进行扩展;拥有便捷的插件扩展机制和丰富的插件,且 jQuery 兼容各种主流浏览器。jQuery 依旧执行 DOM 的增、删、改、查、事件绑定操作,可以说 jQuery 是 DOM 的延续;jQuery 对 DOM 操作的每一步都进行了简化,是用函数来解决一切问题(jQuery就是函数库)。但是 jQuery只有PC端,没有移动端,而且只对 DOM 操作的每一步进行了简化,没有减少步骤,所以用的会越来越少。二、jQuery的使用        到官网jQuery进行下载即可,下载版本后引入网页。1. 将 jQuery 引入网页的方法(1)将 jquery.js 文件下载到项目本地文件夹,用相对路径引入<script src="js/jquery-1.11.3.js">(2)引入 CDN 网络中的 jquery.js 文件         CDN 网络可在全球范围共享一个文件;任意地区的一个客户端想用 CDN 网络中的文件时,CDN 网络都会从距离这个客户端网络最优的服务器下载资源给客户端。<script src="官网提供的CDN网址"> //eg:微软提供的cdn网址: <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.3.js">举例:对比 DOM 与 jQuery 写法;三、jQuery原理1. 引入 jquery.js 文件后,会在内存中新增一种类型,包括:(1)构造函数:创建该类型的子对象;(2)原型对象:集中保管该类型所有子对象共用的方法。2. 使用 jQuery 函数库中的函数时,需要先创建 jQuery 类型的子对象//标准写法 var jq子对象=new jQuery(选择器); //简写 var jq子对象=jQuery(选择器) var jq子对象=$(选择器) //$相当于new jQuery 1.查找DOM元素 2.创建jQuery对象 只有 jQuery 子对象才能访问 jQuery 原型对象中的简化版共有方法。原生的 DOM 元素对象无权使用 jQuery 原型对象中的简化版函数。3.  jQuery 中事件处理函数里的 this        .click 会翻译为 .οnclick=function(){ ... },再执行,所以 .click() 中的 this,其实还是 .onclick 里的 this。与 DOM 中的 this 完全一样,都指向正在点击的当前原生 DOM 元素对象本身;jquery 中所有事件处理函数中的this都必须用 $() 包裹起来(包装),形成一个 jQuery 子对象,才可以使用 jQuery 函数库中的函数。四、 jQuery API三大特点1.自带for循环遍历        只对 jQuery 查找结果对象调用一次简化版函数,就可以自动遍历查找结果中每个 DOM 元素,自动为每个 DOM 元素应用多用的 DOM 操作2.一个函数两用        和修改相关的函数,都既能用于修改新值,又能用于获取旧值;        调用函数时,没有传新值参数,函数默认执行获取旧值操作,        调用函数时,传了新值参数,函数自动改为执行修改为新值操作。举例:有多个按钮,记录每个按钮的单击次数;<body> <h1>jQueryAPI特点</h1> <button id="btn1">click me(0)</button> <button id="btn2">click me(0)</button> <button id="btn3">click me(0)</button> <script src="js/jquery-1.11.3.js"></script> <script> //为三个按钮绑定单击事件,记录单击次数 //DOM 4步 //1. 查找触发事件的元素 var $btn = $("button"); //2. 绑定事件处理函数 $btn.click(function () { //3. 查找要修改的元素:本例中改当前按钮,所以用this var $this = $(this); //4. 修改元素 var n = parseInt( $this.html().slice(9, -1) ); n++; $this.html(`click me(${n})`) }); </script> </body>五、查找元素        jQuery 主要通过选择器的方式查找元素,除了原始 CSS 选择器之外,还添加了额外 jQuery 专属的选择器。1. 子元素过滤选择器(css选择器):first-child所有父元素下第一个直接子元素:last-child所有父元素下最后一个直接子元素:nth-child(i) 所有父元素下第i个直接子元素:only-child  所有父元素下唯一的一个子元素注意:css中下标从1开始举例:使用子元素过滤选择器选择指定元素;<body> <h3>子元素过滤选择器.</h3> <ul> <li>child1-basic0</li> <li>child2-basic1</li> <li>child3-basic2</li> </ul> <ul> <li>child1-basic3</li> <li>child2-basic4</li> <li>child3-basic5</li> </ul> <ul> <li>child1-basic6</li> </ul> <script src="js/jquery-1.11.3.js"></script> <script> //查找每个ul中第一个li,让其字体颜色变为红色 $("ul>li:first-child").css("color", "red"); //查找每个ul中最后一个li,让其边框变为绿色 $("ul>li:last-child").css("border", "1px solid green"); //查找每个ul中处于偶数位置的,让其背景变为黄色 $("ul>li:nth-child(2n)").css("background", "yellow"); //查找每个ul中第2个li,添加蓝色阴影 $("ul>li:nth-child(2)").css("box-shadow", "0 0 10px blue"); //查找作为ul下唯一子元素的li,设置20px内边距 $("ul>li:only-child").css("padding", "20px"); </script> </body>2. 基本过滤选择器(jQuery专属)        先将所有符合要求的元素集中保存到一个大的集合中从0开始统一编号,按元素在集合中的统一编号来选择指定的元素。举例:使用基本过滤选择器选择指定元素;<body> <h3>基本过滤选择器.</h3> <ul> <li>child1-basic0</li> <li>child2-basic1</li> <li>child3-basic2</li> </ul> <ul> <li>child1-basic3</li> <li>child2-basic4</li> <li>child3-basic5</li> </ul> <ul> <li>child1-basic6</li> </ul> <script src="js/jquery-1.11.3.js"></script> <script> //查找第一个li,字体变化红色 $("li:first").css("color", "red"); //查找最后一个li,边框变为绿色 $("li:last").css("border", "1px solid green"); //查找处于(正常人眼)偶数位置的li,背景变为黄色 $("li:odd").css("background", "yellow"); //查找第2个li,添加蓝色阴影 $("li:eq(2)").css("box-shadow", "0 0 10px blue"); </script> </body>3. 内容过滤器(jQuery专属)         根据元素的内容不同来选择元素。:contains(文本)选择内容中包含指定文本关键字的元素:has(其它选择器)选择子元素中包含符合选择器要求的元素的父元素:parent选择内容非空的元素:empty 选择内容为空的元素举例:使用内容过滤选择器选择指定元素;<body> <div class="container"> <h1>内容过滤选择器</h1> <button>提交订单</button> <button>Submit注册信息</button> <button>马上提交</button> <button>清空重填</button> <hr /> <div class="alert"></div> <div class="alert"> <span class="close">×</span> </div> </div> <script src="js/jquery-1.11.3.js"></script> <script> //选择包含"提交"二字的按钮,变为绿色按钮 $("button:contains(提交)").css("background-color", "green"); //选中包含.close按钮的.alert元素,让它们变为红色的警告框 $(".alert:has(.close)").css("background-color", "red"); //选中不包含.close按钮的.alert元素,让它们变为绿色的警告框 $(".alert:not(:has(.close))").css("background-color", "green"); //选择内容为空的.alert元素,添加红色阴影 $(".alert:empty").css("box-shadow", "0 0 10px red"); //选择内容不为空的.alert元素,添加绿色阴影 $(".alert:parent").css("box-shadow", "0 0 10px green"); </script>4. 可见性过滤(jQuery专属)        根据元素是否可见来选择元素;:visible选择可见的元素:hidden选择不可见的元素举例:使用 :hidden 选择不可见的元素;<body> <div class="container"> <h1>可见性选择器</h1> <div id="d1" style="display: none">lorem</div> <div id="d2" style="visibility: hidden">lorem</div> <div id="d3" style="opacity: 0">lorem</div> <input id="d4" type="hidden" name="aa" value="bb" /> </div> <script src="js/jquery-1.11.3.js"></script> <script> console.log($('div.container>:hidden')) </script> </body>5. 表单元素过滤选择器(jQuery专属)        根据表单元素的类别不同来选择不同的表单元素。:input专门选择4大类表单元素(input, select, textarea, button):text选择type="text"的普通文本框:password选择type="password"的密码框:checkbox选择type="checkbox"的复选框:radio 选择type="radio"的单选按钮举例:点同意时启用元素,不同意则禁用元素;<body> <form> 用户名:<input disabled></br> 密码:<input type="password" disabled></br> <input type="checkbox">我同意本站的使用条款<br> <input type="submit" value="提交注册信息" disabled /> </form> <script src="js/jquery-1.11.3.js"></script> <script> //DOM 4步 //1. 查找触发事件的元素 $(":checkbox") //2. 绑定事件处理函数 .click(function () { //3. 查找要修改的元素 var $others = $(":input:not(:checkbox)") //4. 修改元素 //如果当前checkbox是选中的 if (this.checked == true) { // 则启用其他元素 $others.prop("disabled", false); } else { // 否则禁用其他元素 $others.prop("disabled", true); } }) </script> </body>
0
0
0
浏览量532
青椒肉丝加点糖

CSS(一)概述、选择器、选择器优先级

一、CSS概述1. 前端HTML、Javascript、CSShtml:超文本标记语言。用于网页的结构搭建和页面布局。css:层叠样式表。用于网页的修饰,样式的渲染。javascript:解释型的编程语言。用于与页面的交互。2. CSS语法规范(1)内联样式        内联样式也叫行内样式,就是在 html 文件中的 html 标签中,用 style 属性样式值来完成渲染。内联样式将样式写在标签里,缺点是杂乱且不易于修改,复用性差;优点是可以指定当前标签,更加直接。<!-- 内联样式 --> <span style="样式声明"></span>(2)内部样式        在网页头部<head></head>中增加一对<style></style>标签,在 style 中定义样式。特点是需要选择器查找到元素并嵌入 HTML 文件,只能在当前页面使用,优先级低于内联样式(不建议用于项目)。<head> <!-- 内部样式 --> <style> h2 { background-color: lightpink; color: red; } </style> </head>(3)外部样式        单独创建 CSS 文件,在 HTML 文件的 head 标签中引入。<head> <!-- 外部样式 --> <link rel="stylesheet href="01.css"> </head>        href 为超文本引用,引用 css 文件路径,rel 属性指文件与当前HTML的关系(必写)。外部样式所有页面都可以使用,是项目中最重要的样式使用方式。二、CSS选择器        要使用 css 对 HTML 页面中的元素实现一对一,一对多或者多对一的控制,这就需要用到 CSS 选择器。HTML页面中的元素就是通过 CSS 选择器进行控制的。1. 基础选择器(1)通用选择器:使用通配符 * ,选择 HTML 文件中所有元素。最常用的写法是清除浏览器内外边距,如下: *{margin:0;padding:0}(2)元素选择器:也叫标签选择器,直接使用标签的名字来选择 HTML 元素。权重值为1h1 {color: teal;} div {color: green;}(3)id 选择器:只针对一个元素,一般不作为样式渲染的选择器使用。#getblue {color: blue;}(4)类选择器:通过元素的类名即class值选择元素。权重值10.oz {color: purple;} .oo {color: orangered;}        一个元素可以创建多个类名,每个类名之间用空格分开即可。(5)群组选择器:将多种选择器进行组合,把不同的选择器用逗号连接.y,#mybox { background-color: yellow; }2. 关系选择器(1)后代选择器:先代元素(祖先)选择器写在前面,空格后写后代元素选择器。.item span { color: red; }(2)子代选择器:选中某个元素的直接子元素(当前元素下的第一层子元素),与后代不同的是子代选择器的范围更小。body>div>div>div { color: red; }(3)兄弟选择器.l1~li { color: blue; } .s~.nv { color: red; }        注意,前面的为参照元素,后面的为筛选元素,选中的永远是其参照元素后面的兄弟元素。(4)相邻选择器:同一层的关系选择器,可以选中参照的元素后面紧挨着的被参照元素的选择器。.o1+span { color: red; }3. 伪类选择器        伪类选择器的作用是匹配同一个元素,设置其不同状态下的样式。常用的伪类有: a:link { color: green; } div:hover { background-color: salmon; } button:hover+div { background-color: red; }4. 伪元素选择器        用于设置元素的“指定部分”的样式。::before 元素最前边部分 ::after 元素的最后边部分 div::before { content: "欢迎您,"; font-weight: bolder; font-size: 26px; }需要注意content属性必须写,但值可以为空。三、CSS优先级1. 优先级原则(1)顺序读取:相同类型选择器采用顺序读取后来的优先。(2)选择器优先级:不同类选择器,按照权重原则(id选择器100,类选择器10,元素选择器 1)。(3)继承:制定样式的优先级大于继承样式的优先级。(4)多个选择器一起使用:根据权重值累加比较值后采用优先级。2. 最高优先级 - !important        直接获取最高优先级,但注意内联样式不能加 !important。用法如下:.d1{ background-color: rgb(22, 92, 161) !important; } <!-- 表示类名为d1的元素具有最高优先级 -->3. 优先级的比重大小        按引入方式:内联样式 > 内部样式 > 外部样式        按元素:id 选择器(100)> 类选择器(10)> 元素选择器(1)
0
0
0
浏览量1630
青椒肉丝加点糖

JS 高级(六)ES6的特性与功能

ES6: (ECMAScript第六个版本)1. 模板字符串在旧 js 中,拼接字符串只能用+,这样极容易和算术计算的加法计算混淆,所以就需要用到模板字符串,它是一种支持换行、动态拼接内容的特殊字符串格式。模板字符串的使用:a. 整个字符串用一对儿反引号` `包裹;b. 在反引号中可以写单引号,双引号,换行等;c. 在反引号中凡是动态拼接的变量或 js 表达式都要放在 ${ } 中。在模板字符串的 ${ } 中,可以放变量、算术计算、三目、对象属性、创建对象、调用函数、访问数组元素等有返回值的合法的js表达式;但不能放没有返回值的js表达式,也不能放分支、循环等程序结构,比如: if  else  for  while...等。举例:使用模板字符串动态拼接各种各样字符串;<script> var uname = "卫国"; console.log(`姓名:${uname}`); var sex = 1; console.log(`性别:${sex = 1 ? "男" : "女"}`); var price = 12.5; var count = 5; console.log(` 单价:${price} 数量:${count} ================ 小计:${price * count} `); var time = 1622773370370; console.log(`下单时间:${new Date(time).toLocaleString()}`); var day = new Date().getDay(); var arr = ["日", "一", "二", "三", "四", "五", "六"]; console.log(`今天星期${arr[day]}`); </script>打印结果如图:2. let在以往的 js 程序中,我们都是用 var 关键字来声明变量,但是这样会有两个问题:首先是会声明提前,打乱程序正常的执行顺序;其次没有块级作用域,导致代码块内的变量会超出代码块的范围,影响外部的变量。块级作用域:JS 中没有,在其他语言中指除了对象 { } 和 function 的 { } 之外,其余 if  else、for、等程序结构的 {} 范围。但是,在 js 中这些 { },都不是作用域,所以拦不住内部的局部变量声明被提前。解决以上两个问题的方法就是使用 let 关键字代替 var 关键字来声明变量。如下举例:<script> // 定义全局变量 var t = 0; function fun1() { //var t;//undefined console.log(`函数一用时6s`); t += 6; // 此处添加如下代码(不执行) if (false) { var t = new Date(); //此处的t被提前到了当前函数fun1的首部,待执行t+=6时,t的值为undefined+6;无法计算,所以结果却少了6秒,且因为if(false)该语句不执行。 //----------------------------------------------------------------------------- // 解决方式: // 将var改为使用let声明变量,第一种写法: // let t =new Date(); // let底层相当于匿名函数自调,所以第二种写法: // (function (true) { // var t = new Date(); // console.log(`上线时间:${t.toLocaleString()}`) // })(); //------------------------------------------------------------------------------ console.log(`上线时间:${t.toLocaleString()}`) } } function fun2() { console.log(`函数二用时4s`); t += 4; } fun1(); //函数一用时6s fun2(); //函数一用时4s console.log(`共耗时:${t}秒`); //使用var时的打印结果:共耗时4秒 缺少了函数一的6秒 </script>let 关键字与 var 相比,不会被声明提前,可以保证程序顺序执行;还可以让程序块也变成了块级作用域(并没有真正变成块级,只是采用了匿名函数自调的方式),保证块内的变量不会影响块外的变量。注意:let 关键字底层的本质其实就是匿名函数自调。let 关键字的三个特点:a. 因为不会声明提前,所以不能在声明变量之前,提前使用该变量。b. 在相同作用域内,禁止声明两个同名的变量!c. let 底层相当于匿名函数自调,所以,即使在全局创建的 let 变量,在 window 中也找不到!<script> console.log(a); // 1.禁止在声明之前,提前使用该变量 //console.log(b); //报错:Cannot access 'b' before initialization let b = 100; console.log(b); // 2.相同作用域内,不允许重复声明同名变量 var a = 10; //let a = 100; //报错:Identifier 'a' has already been declared // 3.即使在全局let的变量,在window也找不到 var c = 10; 默认保存在window对象中 console.log(c); //10 console.log(window.c); //10 console.log(window["c"]); //10 (function () { let d = 100; console.log(d); //100 })(); console.log(window.d); //undefined console.log(window["d"]); //undefined </script>3. 箭头函数箭头函数是对绝大多数匿名函数的简写,今后几乎所有匿名函数都可用箭头函数简化。箭头函数的简化方法遵循三个原则:a. 去掉 function,在()和{}之间加=>b. 如果只有一个形参,则可以省略( )c. 如果函数体只有一句话,则可以省略{ };函数体仅剩的一句话是 return,则必须去掉 return。举例:将各种 function 改为箭头函数;<script> // ------------------------------------------------- // function add(a, b) { // return a + b; // } var add = (a, b) => a + b; //箭头函数写法 console.log(add(3, 5)); //8 // ------------------------------------------------- var arr = [12, 123, 23, 1, 3, 2]; // arr.sort(function (a, b) { // return a - b // }); arr.sort((a, b) => a - b); //箭头函数写法 console.log(arr); // ------------------------------------------------- var arr = ["亮亮", "楠楠", "东东"]; // arr.forEach(function (elem) { // console.log(`${elem} - 到!`) // }) arr.forEach(elem => console.log(`${elem} - 到!`)); //箭头函数写法 // ------------------------------------------------- var arr = [1, 2, 3]; // var arr2 = arr.map(function (elem) { // return elem * 2; // }) var arr2 = arr.map(elem => elem * 2); //箭头函数写法 console.log(arr2); // ------------------------------------------------- var arr = [1, 2, 3, 4, 5]; // var sum = arr.reduce(function (box, elem) { // return box + elem; // }, 0) var sum = arr.reduce((box, elem) => box + elem, 0); //箭头函数写法 console.log(sum); // ------------------------------------------------- // (function () { // var t = new Date(); // console.log(`页面内容加载完成,at:${t.toLocaleString()}`); // })(); (() => { //箭头函数写法 var t = new Date(); console.log(`页面内容加载完成,at:${t.toLocaleString()}`); })(); // ------------------------------------------------- var t = 5; // var timer = setInterval(function () { // t--; // console.log(t); // if (t == 0) { // console.log("boom!!!") // clearInterval(timer); // } // }, 1000); var timer = setInterval(() => { //箭头函数写法 t--; console.log(t); if (t == 0) { console.log("boom!!!") clearInterval(timer); } }, 1000) </script>箭头函数与 this在常规的写法中,当对象中方法需要通过 this 调用属性时,会出现一定的问题,如下代码:<script> var lilei = { sname: "卫国", friends: ["宝国", "爱国", "建国", "护国"], intr() { this.friends.forEach( function (n) { console.log(`${this.sname}是${n}的哥哥!`); } ) } } lilei.intr(); </script>this.friends.forEach 语句中的 this 指代对象 lilei,可以正常调用,但是函数 function 在打印时仍然用到了 this.sname,需要注意,此处的this已经不再指代对象 lilei,由于它处于 function 函数当中,默认指代 window(全局),而全局中是不存在 sname 属性的。以上代码打印效果如下:uname 显示为 undefined。为了解决此问题,我们便可用箭头函数,箭头函数可让函数内的this与函数外的 this 保持一致。所以将以上对象中的函数改用箭头函数:<script> var lilei = { sname: "卫国", friends: ["宝国", "爱国", "建国", "护国"], intr() { this.friends.forEach( // 使用箭头函数 n => console.log(`${this.sname}是${n}的哥哥!`) ) } } lilei.intr(); </script>显示效果如下:所以,我们可以得出结论:a:如果函数中不包含 this,或希望函数内的this与外部 this 保持一致时,就可以改为箭头函数;b:如果不希望函数内的 this 与函数外的 this 保持一致时,就都不能改为箭头函数。4. for of 遍历数字下标的数组或者类数组对象 arguments 时,可以用到多种循环;普通 for 循环既可遍历索引数组,又可以遍历类数组对象,但没有可简化的空间;forEach 循环可以配合 ES6 的箭头函数,很简化,但无法用于遍历类数组对象。ES6 中提供了 for of 循环,只要遍历数字下标,都可用 for of 代理普通 for 循环和 forEach;格式如下:for(var 变量 of 索引数组/类数组对象){ //of会依次取出数组或类数组对象中每个属性值 //自动保存of前的变量中 }举例:使用 for of 点名,并实现计算任意多个数字的和;<script> // 点名 var arr = ["小红", "小兰", "小绿", "王刚"] // for循环遍历 // for (var i = 0; i < arr.length; i++) { // console.log(`${arr[i]} - 到!`); // } // for-of遍历 for (var t of arr) { console.log(`${t} - 到!`); } // 定义函数求任意多个数之和 function add() { var result = 0; //for循环遍历 // for (j = 0; j < arguments.length; j++) { // result += arguments[j] // } // for-of遍历 for (var n of arguments) { result += n; } return result; } console.log(add(1, 4, 5)); //10 </script>然而 for of 也存在以一些问题,无法获得下标位置i,只能获得元素值;更无法控制遍历的顺序或步调。但是绝大多数循环都是从头到尾,一个接一个遍历的,且绝大多数循环不太关心下标位置,只关心元素值,所以 for of 将来用的还是非常多的!各类循环区分:总结起来就是:下标为数字选 for of,下标为自定义字符串选 for in。5. 参数增强参数默认值调用函数时,如果不传入实参值,虽然语法不报错,但是形参会默认为 undefined,而Undefined 极容易造成程序错误!所以在调用函数时,不传入实参值时,为了使形参变量也有默认值可用,不至于是 undefined,就用到默认值。格式如下:function 函数名(形参1=默认值1, 形参2=默认值2, ...){ //调用函数时,给形参传了实参值,则首选用户传入的实参值。如果没有给形参传是实参值,则形参默认启用=右边的默认值。 }举例:使用参数默认值解决订套餐问题;<script> // 定义一个点套餐的函数 function order( zhushi = "香辣鸡腿堡", xiaochi = "烤鸡翅", yinliao = "可乐" ) { console.log(` 您点的套餐为: 主食:${zhushi} 小吃:${xiaochi} 饮料:${yinliao} `); } // a点默认套餐 order(); // b自定 order("牛肉汉堡", "鸡米花", "雪碧"); // c只换主食 order("烤鸡"); </script>剩余参数(rest)箭头函数虽然好用,但不支持类数组对象 arguments,如果箭头函数遇到参数个数不确定时,就需要用剩余参数语法来代替 arguments。格式:var 函数名=( ...数组名 )=>{ //将来传入函数的所有实参值,都会被...收集起来,保存到...会指定的数组中。 }剩余参数的优点是支持箭头函数,生成的数组是纯正的数组类型,所以可使用数组家所有函数自定义数组名,比 arguments 简单的多。而且还可以和其它形参配合使用,只获得其它形参不要的剩余参数。格式如下:var 函数名=(形参1, 形参2,...数组名)=>{ }举例:使用剩余参数语法计算不同员工的总工资;<script> // 定义计算员工总工资的函数 function add(ename, ...arr) {//计算除ename之外的剩余参数 console.log(arr); var total = arr.reduce( function (m, n) { return m + n; }, 0 ); console.log(`${ename}的总工资为:${total}`); } add("李雷", 10000, 200, 3000); add("韩梅梅", 5000, 500, 300, 1200, 200); </script>展开运算符(spread)apply 拆散数组时,强迫我们必须提供一个替换 this 的对象,那是因为 apply() 本职工作不是拆散数组,而是替换 this,是在替换 this 同时,顺便拆散数组。所以,今后若希望单纯拆散数组,都用...展开运算符。格式:函数名(...数组);展开运算符的原理是...先将数组拆散为多个实参值,再依次分别传给函数的每个形参变量。举例:获取数组中的最大值<script> // 获取数组中的最大值 var arr = [1, 5, 6, 8]; // 错误写法 console.log(Math.max(1, 5, 6, 8)); console.log(Math.max(arr)); // 正确,但必须提供一个替换this的对象 console.log( Math.max.apply(null, arr), Math.max.apply(arr, arr), Math.max.apply("", arr), Math.max.apply(Math, arr) ); // 使用展开运算符 console.log(Math.max(...arr)); </script>语法糖(拓展):        i. 复制一个数组: var arr2=[...arr1];        ii. 合并多个数组和元素值: var arr3=[...arr1,值,...arr2,值];        iii. 复制一个对象: var obj2={ ... obj1 }        iv. 合并多个对象和属性: var obj3={ ...obj1, 属性:值, ...obj2, 属性:值 }
0
0
0
浏览量2009
青椒肉丝加点糖

HTML(二)列表、表格、表单元素

一、列表1. 有序列表(<ol> </ol>)        第一层嵌套内只能包含 <li></li> 列表项标签,列表项标签可以包裹任何标签和文本,属于块级元素。有序列表有以下几个属性:2. 无序列表(<ul> </ul>)       第一层嵌套内只能包含<li></li>列表项标签,同有序列表。有以下几个属性:        有序列表和无序列表第一层内必须包含列表项标签,文本写在列表项标签内。3. 自定义列表(<dl> </dl>)        <dt></dt>  列表标题        <dd></dd> 文本和元素<dl> <dt>国内电影</dt> <dd>流浪地球</dd> <dd>来电狂想</dd> <dt>国外电影</dt> <dd>惊奇队⻓</dd> <dd>美国队⻓</dd> </dl> 4. 嵌套列表        有序、无序以及自定义列表相互嵌套。举例:<!-- 嵌套列表 --> <ul> <li>MOBA类游戏 <ol> <li>王者荣耀 <ul type="circle"> <li>武则天</li> <li>嬴政</li> <li>不知火舞</li> </ul> </li> <li>英雄联盟 <ul type="circle"> <li>无极剑圣</li> <li>疾风剑豪</li> <li>暗裔剑魔</li> </ul> </li> </ol> </li> <li>第一人称射击 <ol> <li>和平精英</li> <li>使命召唤</li> <li>生化危机</li> </ol> </li> <li>经营类 <ol> <li>大富翁</li> <li>模拟人生</li> <li>城市天际线</li> </ol> </li> </ul> 二、表格1. 表格标签2. 表格的行列3. 表格标签相关属性4. 拆分与合并        拆分合并之后需要删除多余的行或列。三、表单元素1. 表单标签(<form></form>) 表单用于搜集不同类型的用户输入,该标签不能单独使用,需要在 form 元素中加入 input 等标签共同使用。2. input标签及控件      <input/>元素是最重要的表单元素,有不同的type属性3. 标记标签(<label> </label>) 不会向用户呈现任何特殊效果,内联元素,不自占一行 label 标签的 "for" 属性可把 label 绑定到另外一个元素,把 "for" 属性值设为相关元素的id 值即可。4. 菜单标签(<select> </select>)下拉菜单标签,不能单独存在,只能包裹option。 <option></option> 菜单选项,multiple 属性代表该下拉菜单可以多选。<select name="cd" id="city" multiple> <option value="0">请选择</option> <option value="1">北京</option> <option value="2">天津</option> </select>5.文本域(<textarea> </textarea>)具有滚动条的多行文本输入控件。
0
0
1
浏览量2019
青椒肉丝加点糖

JavaScript基础(一)js环境搭建、变量常量、数据类型及转换、运算符

JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式、声明式、函数式编程范式。  自ES6出世以来,JavaScript已成为世界上唯一一种可以同时包揽前后端的编程语言。一、JS开发环境的搭建 JavaScript 开发环境分为浏览器端和服务器端。所谓浏览器端就是 JS 代码通过浏览器自带的 JS 解释器来执行,典型代表就是五大浏览器:谷歌、火狐、edge、safari、欧朋。浏览器端执行需要创建一个 .js 文件和一个 .html 文件,然后将 .js 文件嵌入到 .html 文件中。<script src="01.js"></script>嵌入之后用浏览器打开.html文件即可。服务器端则需要用到 Node.js,它是运行在服务器端的开发环境。需要使用时下载安装,下载地 www.nodejs.org,执行方式也较为简单快捷,只需在命令提示符 cmd 下输入:node 空格  然后拖拽要运行的文件。如下:那么,如何检测自己是否安装Node了呢?在cmd命令提示符下输入node -v;如果显示出版本号,则表示Node已成功安装。二、变量和常量    变量是存储数据的容器;常量同变量一样用于存储数据,但常量声明以后不允许重新赋值。    声明变量使用关键字var,声明常量使用关键字const。示例://变量声明 var x = 1;//表示在内容中开辟一块空间并命名为x,把1保存至这个空间中 var y = 2; var ename = '张三';//使用字符串时需要加引号 //常量声明 const pi = 3.14;三、数据类型        五大原始类型:数值型、字符串型、布尔型、未定义型、空数值型 number,包括二进制、八进制和十进制。var n1 = 10;//10进制 var n2 = 012;//8进制 var n3 = 0xa;//16进制 var n5 = 3.1415E+2;//浮点型字符串型 string,被引号包含的数据即为字符串。 var str1 = 'abc'; var str2 = '8';布尔型 Boolean,只有两个值:true、false,通常用于保存只有两个状态的数据,例如是否在线、是否登录、一些运算符的结果等。未定义型 undefined,只有一个值 undefined,代表一个空值,例如声明了变量未赋值。空 null,只有一个值 null,类型为 object,通常结合对象一起使用检测数据类型需要用到 typeof,使用方法如下:var p = null;//定义一个变量为空 console.log(p,typeof p);//打印并用typeof检测数据类型,显示为null四、数据类型的转换首先是隐式转换,它是运算过程中自动产生的数据转换,其实是自动调用了Number函数(1)数字+字符串   数字转换为字符串后拼接(2)数字+布尔型   布尔型转换为数字,true--1,false--0(3)布尔型+字符串   布尔型转换为字符串后拼接(4)undefined+数字  undefined转为NaN(5)减乘除时,数据自动转为数值var n1 = 2 + '3';//23 var n2 = 2 + true;//3 var n3 = 'zxc' + false;//zxcfalse var n2 = '3' - 1;//2 var n3 = '2' * true;//2第二个是强制转换,需要用到函数(1)强制转换为数值型 Number( )var n1 = Number("1"); //1 var n1 = Number(true); //1 var n2 = Number(false); //0 var n3 = Number(undefined); //NaN var n4 = Number(null); //0 var n5 = Number("1a"); //NaN(2)强制转换为整型 parseInt( ) ,强制将字符串和小数转为整型var p1 = parseInt("3.14"); //3 var p2 = parseInt("6.18a"); //6 var p3 = parseInt("a6.18"); //NaN var p4 = parseInt(5.9); //5(3)强制转换为浮点型 parseFloat( ) ,强制将字符串转换为浮点型var f1 = parseFloat("3.14"); //3.14 var f2 = parseFloat("6.18a"); //6.18 var f3 = parseFloat("6a"); //6 var f4 = parseFloat("a6.18"); //NaN(4)数值和布尔型强制转为字符串 toString( )var num = 5; var str = num.toString( ); //"5"五、运算符在学习运算符之前,先来了解以下“表达式”的定义:由数据本身或者由运算符连接的操作数据组成的形式称为表达式,也就是说,运算符所连接的数据均称为表达式。1. 算数运算符即我们平常所用的加(+)、减(-)、乘(*)、除(/),还有取余(%)、自增(++)、自减(--)。加减乘除以及取余较为简单,不做探讨。通过一组代码来理解自增和自减:var a2 = 5; var a3 = a2++;//先将a2的值赋给a3,再自增 console.log(a2,a3);//6 5var a4 = 7; var a5 = ++a4;//a4先自增,再赋值给a5 console.log(a4,a5);//8 8 可以看出,如果自增用在变量后面,则是先使用变量的值参与计算,随后再进行变量加1;而如果自增用在变量前面,则是先将变量进行自增以后再参与计算,自减同理。2. 比较运算符等于“==”只比较两者的值是否相同,全等于“===”同时比较类型和值;不等于“!=”只比较值是否不同,不全等于“!==”同时比较类型和值,有一个不等即为 true;数字与字符串比较时,字符串转为数值;字符串之间比较时,比较首个字符的 Unicode 码;NaN 和任何值比较均返回 false,NaN == NaN 也为 false;console.log(2 == '2');//== 只比较值的大小,都为2,所以显示true console.log(2 === '2');//=== 比较值和类型,值虽然都为2,但前者为数值型,后者为字符串,所以显示false3. 逻辑运算符&& 逻辑与,关联的两个条件都为true,结果为true|| 逻辑或,关联的两个条件有一个为true结果即为true  ,! 逻辑非,取反 eg:!true = false逻辑运算符中比较重要的为短路逻辑:var a = 2;a > 3 && console.log(num);        如上代码,a 的值为 2,逻辑与判断中,第一个表达式为 a>3,而 2 不大于 3,说明此处为false,由于这里使用的运算符为逻辑与 &&,只有前后两个条件都为 true 时整体才为 true,所以第二个表达式就没有 必要再运行了,此时就是发生了短路逻辑。换句话说,短路逻辑的看重点就是在于是否执行第二个表达式。4. 位运算符        模拟计算机底层的运算,先将数据转为2进制进行运算,运算结束后再将结果转回10进制& 按位与,上下两位都是1,结果为1,否则为0;| 按位或,上下两位有一个1则结果为1;^ 按位异或,上下两位不同为1,相同为0;>> 按位右移,删除末尾的位数(原基础上除以2再取整);<< 按位左移,在末尾补0(原基础上乘以2)。//按位与 console.log(3 & 5);//011 & 101 == 001 == 1 console.log(5 & 8);//0101 & 1000 == 0000 == 0 //按位或 console.log(4 | 7);//100 | 111 == 111 == 7 //按位异或 console.log(6 ^ 9);//0110 ^ 1001 == 1111 == 15 //按位右移 console.log(9 >> 1);//1001 >> 1 == 0100 == 4 //按位左移 console.log(5 << 1);//101 << 1 == 1010 == 105. 赋值运算符        所谓赋值运算,就是先进行运算,再进行赋值var a = 1; a += 3;//4 a = a + 3;//43. 三目运算符一目运算符:由一个运算符连接的一个操作数据或者表达式  !  ++  --二目运算符:由一个运算符连接的两个操作数据或者表达式三目运算符:由两个运算符连接的三个操作数据或者表达式 格式:条件表达式 ? 表达式1 : 表达式2;如果条件表达式为 true,执行表达式1,如果条件表达式为false,执行表达式2。var a = 1,b = 2; a > b ? console.log('对') : console.log('错');在以上函数中,a为1,b为2,首先判断a是否大于b,如果大于,则执行 console.log('对'),如果小于,则执行 console.log('错')。所以此语句输出结果为:错。
0
0
0
浏览量490
青椒肉丝加点糖

JavaScript基础(二)选择语句、循环语句

 在JavaScript当中,程序的执行方式分为选择执行、循环执行、顺序执行。通常的程序代码都是顺序执行。var a = 3; console.log(a);        比如上面这两行简单的代码,先赋值,再打印,这就是顺序执行。  我们这期的重点为选择执行和循环执行,选择执行的典型代表就是流程控制,如if语句、if-else语句、if-else嵌套、switch-case语句,接下来我们将依次进行描述。而循环执行则是常见的while循环、do-while循环、for循环和循环嵌套。一、流程控制(选择执行)1. if语句if ( 条件表达式 ) { 语句块 }它的格式很简单,常用来进行判断。先判断 if 之后的条件是否满足,如果满足则执行语句块。比如判断一个人的年龄,是否为成年人,代码如下:var age = 30; if (age >= 18){ console.log('成年人');//"成年人" }定义了年龄为30,使用if进行判断,30大于18,所以打印“成年人”。需要注意的是,如果 if 后的语句块中只有一行代码,则 { } 可以省略。2. if-else语句if ( 条件表达式 ) { 语句块1 }else{ 语句块2 }if-else 语句与 if 语句的区别仅仅在于加了else 判断,先判断 if 后的条件是否满足,如果满足执行语句块1,不满足则执行 else 后的语句块2。再拿上面的成年人来进行判断:var age = 12; if (age >= 18){ console.log('成年人'); }else{ console.log('未成年人'); }定义年龄 age 为12,12不大于18,所以要执行else后的语句,即打印“未成年人”。3. if-else嵌套if ( 条件表达式1 ) { 语句块1 }else if { 条件表达式n ){ 语句块n }else { 语句块n+1( 前面全为false才执行此语句块 ) }if-else嵌套则是多个 if-else 语句的组合,可以对多个条件进行判断。举个打印成绩的例子:var f = 75; if (f > 100 || f < 0){ console.losg('非法的成绩!'); }else if (f >= 90){ console.log('优秀'); }else if (f >= 80){ console.log('良好'); }else if (f >= 70){ console.log('中等'); }else if (f >= 60){ console.log('及格'); }else{ console.log('不及格'); }定义分数为75分,则依次往下进行判断,直到符合条件执行该条件下的语句块。该题打印结果为“中等”。4. switch-case语句switch ( 表达式 ){ case 值1: 语句块1 break;(结束执行,跳出当前语句) case 值n: 语句块n break; default: 语句块n+1( 前面全为false才执行此语句块 ) }switch-case 语句的运行方式为:先判断 switch 后的表达式的值,看它的值满足哪一个 case 的值,如果满足则执行该 case 后的语句块,执行结束后直接跳出(break)语句,如果前面都不满足,则执行 default 之后的语句块。switch-case 语句也可用来判断成绩区间:var score = 90; if (score < 0 || score > 100){ console.log('成绩错误!!!'); } var end = parseInt(score /= 10); switch(end){ case 10: case 9: console.log('优秀'); break; case 8: console.log('良好'); break; case 7: console.log('中等'); break; case 6: console.log('及格'); break; default: console.log('不及格!'); }switch-case 使用过程中需要注意以下几点:        表达式在与case后面的值比较的时候,用的是全等于(===)即同时判断值和类型。        switch-case只能是全等于的比较,但结构更为清晰,执行效率更高二、循环语句(循环执行)1. while循环初始值 while ( 循环条件 ){ 循环体 增量 }while 循环的执行为先判断循环条件,循环条件为 true,进入循环,false 则跳出。举一个简单的小例子:var i = 1; while (i <= 10){ i++; console.log('123456'); }定义 i 的值为1,条件为 i<=10,如果 i 满足条件则进入循环,i 自增后打印“123456”,直到 i 的值大于10为止。该程序结果为打印10次“123456”。2. do-while循环初始值 do { 循环体 增量 } while ( 循环条件 ) ;do-while 可以认为与 while 相反,先进行循环,再判断循环条件,结果为 true 继续进入循环,结果为 false 则结束。var i = 1; do{ console.log(i); i++; }while (i <= 10);该程序结果为打印1到10,先进行打印,再判断条件,直到条件判断为 false 跳出循环。3. for循环for ( 初始值 ; 循环条件 ; 增量 ) { 循环体 }for 循环可能是在编程过程中使用最多的一个循环,它的执行方式为从初始值开始,判断循环条件,结果为 true 则执行循环体,最后执行增量,增量之后再执行循环条件。直至循环条件为 false时循环结束。for (var i = 1;i <= 10;i++){ console.log(i); }该例子同样为打印1到10。4. 循环嵌套        所谓循环嵌套就是在一个循环体内部又出现了其他的循环,任意两个循环之间都可以进行相互嵌套。嵌套后外层循环控制循环的行数;内层循环控制每一行拼接的数量。//外层循环 for (var i = 1;i <= 5;i++){ //内层循环 for (var j = 1,str = '';j <= i;j++){ str = str + '*'; } console.log(str); }如上代码,两个 for 循环嵌套,外层循环控制该循环为5行,内层则控制打印的行内容为‘*’且*的数量不断自增,效果如下:三、选择与循环语句例题        了解了选择与循环语句后,我们通过几道例题来巩固一下://1.一张纸可以折无限次数,纸的厚度为0.03毫米,问:折多少次可以达到珠穆朗玛峰高度8848米? var h = 0.00003;//初始化纸的厚度为0.00003 var count = 0;//count用于记录次数 do { h *= 2;//h = h * 2 count++; } while (h <= 8848);//直到h的值大于8848,跳出循环 console.log(count);//打印次数//2.用while函数写出1~100之间所有偶数的和 var i = 1; var sum = 0;//sum用于记录最后的和 while (i <= 100){//判断条件i为1~100 if (i % 2 === 0){//与2取余结果为0的则为偶数 sum += i; } i++; } console.log(sum); *///3.打印九九乘法表 for (i = 9;i >= 1;i--){ //内层循环,控制每行列数 for (j = 9,str = '';j >= i;j--){ //列 + * + 行 + = + 乘积结果 str = str + j + '*' + i + '=' + (j*i) + ' '; //将第3,4行的第2列后加一个空格 if (i === 9 && j === 1){ str = str + ' '; } } console.log(str);//每一行拼接结束后即打印 }//4.打印2000~2100之间前10个闰年 for (var year = 2000,count = 0;year <= 2100;year++){ //count用于记录闰年的个数 if (year % 4 === 0 && year % 100 !== 0 || year % 400 ===0){ console.log(year); count++; } if (count === 10){ break; } } console.log(count);
0
0
0
浏览量2011
青椒肉丝加点糖

JavaScript基础(四)对象、数组、对象与数组的常用API

一、对象        俗话说,万物皆对象。在真实生活中,汽车是一个对象。汽车有诸如车重和颜色等属性,也有诸如启动和停止的方法。在JavaScript中,对象是一组属性与方法的集合,属于引用类型数据。1. 对象的创建        在JavaScript中,自己创建的对象就是自定义对象,常用创建方式为字面量方式,格式如下:{ 属性名 : 属性值 , 属性名 : 属性值 ...... }可以看出,用字面量创建对象很简单,就是直接在大括号里写属性名:属性值。属性名的引号可以省略,但属性名含有特殊字符时必须添加引号。例如:创建一个手机对象,带有颜色、品牌、大小、产地属性,同时因为made-in中间有特殊字符,所以该属性名需要加引号。var phone = { color:'黑色', brand:'HUAWEI', size:6.5, 'made-in':'北京' };第二种创建方式为通过内置的构造函数创建 ,格式如下:new Object( );此语句表示创建一个空对象,它需要单独的添加每个属性,例如:var car = new Object();//创建空对象car car.color = '黑色';//添加属性 car.brand = '红旗'; car.width = '2.10米'; car.length = '3.5米'; console.log(car);2. 对象属性的访问格式为:对象.属性名;也可以使用对象[ ' 属性名 ' ];以下代码使用了这两种方式:var laptop = { lid:1, title:'手机', price:3600, 'shelf-time':'2021-02-02' } //console.log(laptop); //访问属性 console.log(laptop.lid);//1 console.log(laptop['shelf-time']);//2021-02-02 console.log(laptop['title']);//手机此外,也可以对属性进行修改或者添加:laptop.price = 5699;//将价格修改为5699 laptop.pic = 'huawei.jpg';//添加图片属性3. 遍历对象属性        遍历属性是通过循环的方式(for-in循环)一次次的访问对象中的每个属性,格式为:  for ( var k in 对象 ) { }   其中,k 代表每个属性名,对象 [k] 代表属性名对应的属性值。看一道例题://创建对象,保存一组成绩,遍历对象的属性,获取每一个成绩,计算出总成绩和平均成绩 var score = new Object(); score.chi = 89; score.eng = 80; score.mat = 100; score.che = 79; score.his = 91; var sum = 0,count = 0;//sum记录成绩之和,count记录科目数 for (var k in score){//开始遍历,获取各科成绩 console.log('课程:' + k,'成绩:' + score[k]); sum = sum + score[k]; count ++; } console.log('总成绩为:' + sum); console.log('平均成绩为:' + sum / count);4. 检测属性是否存在(1)对象名.属性名 === undefined;存在返回false,不存在返回true(2)对象名.hasOwnProperty('属性名');存在返回true,不存在返回false(3)'属性名' in 对象名;存在返回true,不存在返回falsevar emp = { eid:1, ename:'aaa', sex:'男' }; console.log( emp.salary === undefined );//true 说明不存在 console.log( emp.hasOwnProperty('salary'));//false 说明不存在 console.log('salary' in emp);//false 不存在5. 对象的方法        方法对应的是一个函数,如下代码:name是属性,而使用了函数的play就是方法。var person = { name:'张三',//成员属性 play:function( ){//成员方法 this //指代调用方法时的对象,跟所在的对象没有关系 } }; person.play( ); //调用方法方法的调用和属性基本相同,格式如下:var js = { sum:function(a,b){ return a + b; }, ax:function(c,d){ return c * d; } }; console.log( js.sum(10,1) ); console.log( js.ax(3,5) );二、数组对象        数组是数据的一组集合,每个数据称作元素,特点是便于操作数据。1. 数组的创建        创建方式类似于对象,有字面量创建和内置函数创建,格式如下://数组字面量 var p = ['张三','李四',20,true]; var salary = [12000,4500,6500,12000,15000]; var emp = ['手机','冰箱','电脑','洗衣机','空调']; var car = ['红旗','大众','本田','福特','吉利','别克',]; //内置函数创建 var arr = new Array('huawei','xiaomi','oppo','vivo');2. 访问数组        格式:数组[下标],下标是数组为每个元素自动添加的编号,从0开始。例如 car[1] 就为大众,emp[0] 就为手机。3. 数组长度        格式:数组.length,用于获取数组元素的个数;需要在数组的末尾添加元素时,只需用到 数组 [ 数组.length ] = 值 即可。4. 数组的遍历for(var i = 0;i < 数组.length;i++){ i //下标 数组[i] //下标对应的元素 }举例:创建salary数组,遍历数组获取各个工资 后求和。var salary = [15000,4500,5400,27000,12000]; for (i = 0,sum = 0;i < salary.length;i++){ sum = sum + salary[i]; } console.log('总工资为:' + sum);5. 数组API API 是 JavaScript 中预定的函数和方法。API 有很多,以下列出比较常用的几种:API用途toString( )将数组转为字符串indexOf( ) 检测数组中是否含有某个元素,返回的是元素的下标,如果找不到则返回-1join( )    将数组转为字符串,同时指定分割的符号 eg:join('-')concat  拼接多个数组,返回一个大的数组 eg:arr1.concat(arr2)reverse( )  翻转数组元素slice( )        截取数组中的元素slice(start,end) ;start是开始的下标,end是结束的下标splice( )      删除数组中的元素push( )        往数组的末尾添加一个或者多个元素,返回的是数组的元素,原数组会发生变化pop( )        删除数组末尾的一个元素,返回的是删除的那个元素,原数组会发生变化unshift( )    往数组的开头添加一个或者多个元素,返回的是数组的元素,原数组会发生变化shift( )        删除数组开头的一个元素,返回的是删除的那个元素,原数组会发生变化用法示例:var arr = ['a','b','c']; console.log( arr.toString() );//数组转字符串 console.log( arr.join('-') );//将数组转为字符串,同时以“-”隔开 var arr1 = ['张三','李四','王五']; var arr2 = ['李健','许巍','朴树']; var arr3 = ['张惠妹','邓丽君','张靓颖']; console.log( arr1.concat(arr2,arr3) );//拼接数组三、各类对象常用APIMath对象Data对象:用于对日期、时间的存储和计算数值对象布尔对象
0
0
0
浏览量583
青椒肉丝加点糖

CSS(三)元素的修饰、背景设置

一、元素的修饰1. 圆角——border-radiusCSS中,任何元素都有四个角: 圆角的取值:1个值:四个角相同2个值:左上右下、左下右上3个值:左上、右上左下、右下  4个值:左上、右上、右下、左下(顺时针)border-radius: 10px; border-radius: 10px 20px; border-radius: 9px 5px 3px; border-radius: 3px 10px 20px 30px;2. 盒子阴影——box-shadow格式:box-shadow: x轴偏移 y轴偏移 羽化 扩展 颜色 内外阴影(可选,默认向外)第一、二个值: x 轴上的偏移量和y轴上的偏移量(正负值)第三个值:模糊半径的大小(羽化)不允许负值第四个值:扩展半径的大小,向四周扩散相等的大小,正值放大,负值缩小第五个值:颜色值第六个值:阴影向内 inset:默认阴影向外扩散box-shadow: 3px 5px 5px 1px green inset;3. 光标的设置4. 元素特有样式(1)表单轮廓 outline格式:outline:width style color; 该属性常用与清空轮廓线。outline: none; outline: 0;(2)列表样式 list-style二、背景1. 背景颜色  background-color: 颜色色值;2. 背景图片  background-image: url(路径);路径可以是绝对路径或者相对路径,注意外部 css 的路径,背景图必须要求元素具有宽度和高度。背景图和img的区别:img具有尺寸,不设置宽度高度,可以直接显示背景图必须设置宽度和高度img图片不可直接写文字,除非在img盒子外部定位背景图是可以在图片上写文字,背景图其实和颜色一样img一般用于产品展示,可以根据素材更新背景图一般左大背景或者更新小图标3. 背景图平铺如果宽高大于图片大小,图片会重复显示;如果宽高小于图片大小,图片会显示不全。4. 背景图定位  background-position背景图定位取值可以是关键词,也可以为正值和负值,正值向右移动负值向左移动。5. 背景图尺寸  background-size在拉伸方向中有宽度拉伸和高度拉伸两种,所以可以指定两个值background-size:x轴拉伸 y轴拉伸;注意在设置大图背景时最好限制最低宽度,这样低于预定宽度时就会出现横向拖拽条保证图片和内容显示完整。6. 简写格式:background:color image repeat position;  四组值用空格分开,没有顺序;举例:.uname { background-image: url(./img/yhm.png); background-repeat: no-repeat; background-position: right; background-size: auto; background-size: auto 100%; }简写后:.uname { background: url(./img/yhm.png) no-repeat right/auto 100%; }
0
0
0
浏览量570
青椒肉丝加点糖

MySQL(二)MySQL部署、建库建表实操示例

一、MySQL 的部署        部署MySQL的第一步是用客户端连接服务器端打开xampp-control,连接MySQL(部分电脑需要用管理员模式打开软件才可正常运行);连接成功后如图,会显示端口号与PID打开"shell"(命令行)进入后如图此时,输入命令 mysql -uroot 实现客户端与服务器端的连接连接成功后显示如下 连接成功以后即可用管理命令查看已有数据库与数据表,示例如下:其余管理操作省略.......二、建库建表        部署完 MySQL 之后,就可以建库建表和数据查询操作了;此时需要用到 SQL 语言,而 SQL 的执行方式有两种:交互模式和脚本模式。交互模式是在客户端输入一行,点击回车,服务端执行一行,适用于临时查看数据;脚本模式是客户端把要执行的命令写在一个脚本文件中,一次性提交给服务器执行,适用于批量操作数据,使用方式为:mysql -uroot<脚本文件路径;在这里我们使用脚本模式,需要用到第二款软件 EditPlus,我们先创建脚本文件,直接创建文本文档设置后缀为 .sql 即可;右键使用 EditPlus 打开,主界面如图;此时,就可以输入SQL语言进行建库建表操作了;#设置客户端连接服务器端的编码 set names utf8; #丢弃数据库,如果存在 drop database if exists web; #创建数据库,设置存储的编码 create database web charset=utf8; #进入数据库 use web; #创建部门表 create table dept( did int primary key auto_increment, dname varchar(8) unique ); #插入数据 insert into dept values(10,'研发部'); insert into dept values(20,'运营部'); insert into dept values(30,'市场部'); insert into dept values(40,'测试部'); #创建员工表 create table emp( eid int primary key auto_increment, ename varchar(8) not null, sex boolean default 1, #1-男 0-女 birthday date, salary decimal(8,2), #999999.99 deptId int, foreign key(deptId) references dept(did) ); #插入数据 insert into emp values(null,'tao',default,'1973-7-15',50000,20); INSERT INTO emp VALUES(NULL,'Tom',1,'1990-5-5',6000,20); INSERT INTO emp VALUES(NULL,'Jerry',0,'1991-8-20',7000,10); INSERT INTO emp VALUES(NULL,'David',1,'1995-10-20',3000,30); INSERT INTO emp VALUES(NULL,'Maria',0,'1992-3-20',5000,10); INSERT INTO emp VALUES(NULL,'Leo',1,'1993-12-3',8000,20); INSERT INTO emp VALUES(NULL,'Black',1,'1991-1-3',4000,10); INSERT INTO emp VALUES(NULL,'Peter',1,'1990-12-3',10000,10); INSERT INTO emp VALUES(NULL,'Franc',1,'1994-12-3',6000,30); INSERT INTO emp VALUES(NULL,'Tacy',1,'1991-12-3',9000,10); INSERT INTO emp VALUES(NULL,'Lucy',0,'1995-12-3',10000,20); INSERT INTO emp VALUES(NULL,'Jone',1,'1993-12-3',8000,30); INSERT INTO emp VALUES(NULL,'Lily',0,'1992-12-3',12000,10); INSERT INTO emp VALUES(NULL,'Lisa',0,'1989-12-3',8000,10); INSERT INTO emp VALUES(NULL,'King',1,'1988-12-3',10000,10); INSERT INTO emp VALUES(NULL,'Brown',1,'1993-12-3',22000,NULL); 如上代码,我们建立了数据库 web,包括员工表 emp 和部门表 dept,并插入了若干数据;接下来将写好的脚本文件提交给服务器;在第一个软件 xampp-control 中两次打开 shell 窗口,以下记为 shell1 和 shell2;第一步:在shell1中输入命令:mysql -uroot < 我们刚写的脚本文件路径,模拟服务器端,如图:第二步:在 shell2 中输入命令:mysql -uroot,连接服务器端,模拟客户端,如图:注:第一步与第二步顺序不可颠倒。接下来在客户端也就是 shell2 中进行相关操作即可,但是shell1不可关闭;查询已有数据库,出现了web,说明我们数据库创建成功。进入数据库,查询库中表格;查询表格数据;此时,数据库与数据表均创建完成,具体查询数据信息用到SQL语言,此处省略......
0
0
0
浏览量2016
青椒肉丝加点糖

MySQL(一)认识MySQL、常用管理命令、列类型列约束、查询语句

一、软件生命周期和计算机数据存储方式1. 软件生命周期        定义期:可行性研究阶段/需求分析阶段;        开发期:概要设计阶段/详细设计阶段/编码实现阶段/测试阶段;        维护期:部署阶段/维护阶段。2. 计算机对数据的存储,有4个方面通过特定的文件如excel、word等存储,只适用于存储小量数据且速度慢;内存,临时存储,运行时会有数据产生并存储,结束运行后数据即销毁;速度快;第三方云服务器,共享;数据库服务器。MySQL属于数据库服务器存储的范畴。二、数据库        数据库的作用就是按照一定的形式组织存放数据,目的是为便于操作数据,即增、删、改、查。数据库的发展历程为:网状数据库-->层次型数据库-->关系型数据库(RDBMS)-->非关系型数据库。1. 常见的关系型数据库SQLite——微型数据库,常用于移动端MySQL——开源RDBMS,是一种关联数据库管理系统,将数据库保存在不同的库中,每个库可包含多个表,表中可以有多行多列的数据,可用于各种操作系统SQL Server——Microsoft开发的中型数据库,只适用于Windows操作系统Oracle——Oracle开发的中大型数据库,可用于各种操作系统DB2——IBM开发的中大型数据库,常与IBM服务器搭配2. MySQL部署结构        MySQL部署分服务器端和客户端,服务器端负责存储维护数据,客户端负责连接服务器端,对数据进行增删改查操作。使用客户端连接服务器端时只需要执行命令:mysql.exe -h127.0.0.1 -P3306 -uroot -p -h,host IP地址/域名 eg:127.0.0.1/localhost(永远指向自己本身的电脑) -P,port 端口(此处为3306端口) -u,user 用户名(root是管理员账户,在root下密码为空) -p,password 密码 此命令也可以简写为:mysql -uroot3. 常用管理命令(必须以英文“;”结尾)quit;  退出连接show databases;  显示当前所有数据库use 数据库名称;  进入指定的数据库show tables;  显示当前数据库下的所有数据表desc 数据表名称;  描述数据表中都有哪些列4. 常用SQL命令以及举例(1)定义数据结构(DDL)drop database if exists jd; //丢弃数据库jd(存在的基础上) create database jd; //创建数据库jd use jd; //进入数据库jd create table student ( id int, name varchar ( 8 ), sex varchar ( 1 ), score int ); //创建表student,包括id、name、sex、score四列(2)操作数据(DML)insert into student values('1','张三','M','99'); //向student表中插入一行数据 delete from user where uid="2";  //删除uid为2的行数据 update user set upwd="666666",isOnline="n" WHERE uid="3"; //修改uid为3的行密码为666666,在线状态为n(3)查询数据(DQL)select * from student; //查询student表中的所有数据三、列类型        列类型指在创建数据表时,指定的列所能存储的数据类型。1. 数值型2. 日期时间型3. 字符串型   字符串型和日期时间型 必须加引号四、列约束列约束的意思是MySQL对要插入的数据进行特定的验证,只有符合条件才允许插入(位于列类型之后)。1. 主键约束  primary key声明了主键约束的列,不允许插入重复,一个表中只能有一个主键约束,通常用于编号列,可加快数据查找速度。自增列 Auto_increment:自动增长,声明了自增列,插入数据时只需要赋值为 null,就会获取最大值然后加1插入。声明了自增列也允许手动赋值。2. 非空约束  not null声明了非空约束的列上禁止插入Null。3. 唯一约束  unique声明了唯一约束的列不允许插入重复的值,但是 unique 允许插入重复的 null 甚至多个 null,一个表中可以有多个唯一约束。4. 默认值约束  defaul可以使用 default 关键字设置默认值,default使用时不加引号。5. 检查约束  check也称自定义约束,用户可以制定约束的条件。但是 MySQL 不支持检查约束,认为会极大影响数据插入数据,后期需要通过 JS 实现。6. 外键约束  foreign声明了外键约束的列称为外键列,这一列取值范围到另一个表的主键中,是为了让两个表建立关联。外键约束用法特殊,常用于创建表的最后一行,外键列要和对应的主键列的列类型保持一致。格式如下:格式:foreign key(外键列) references 另一个表(主键列) eg:foreign key(familyId) references family(fid)五、MySQL查询语句注:以下举例中 ,emp为员工表,dept为部门表1. 简单查询(1)查询特定的列     eg:查询所有员工的编号和姓名 select eid,ename from emp;(2)查询所有的列    eg:查询员工表emp中所有信息 select * from emp;(3)给列起别名       eg:查询所有员工的编号和姓名并起别名 select eid as 编号,ename as 姓名 from emp;(4)显示不同的记录eg:查询有哪些性别的员工 select distinct sex from emp;(5)查询时执行计算eg:查询所有员工姓名及年薪 select ename,salary*12 from emp;(6)查询结果排序     eg:查询所有部门数据,结果按照编号升序排列 select * from dept order by did asc;(7)条件查询             eg:查询编号为5的员工的数据 select * from emp where eid=5;(8)模糊条件查询     eg:查询姓名中含有“e”的员工 select * from emp where ename like "%e%"; % 表示匹配任意个字符, _ 表示匹配一个字符,以上两个匹配符须结合like关键字使用(9)分页查询        当查询的结果中数据太多,一次显示不完,就可以使用分页显示。分页查询需要两个已知条件:当前页码+每页数据量。语法:select * from emp limit 开始查询的值, 每页的数据量;eg:假设每页显示五条数据,分别查出前三页 第1页:select * from emp limit 0,5; 第2页:select * from emp limit 5,5; 第3页:select * from emp limit 10,5; 注意:开始查询的值=(当前的页码-1)* 每页数据量2. 复杂查询(1)聚合查询/分组查询eg:通过员工编号查询员工数量 select count(eid) from emp; eg:查询各部门员工 最高工资,员工数量,平均工资 select max(salary),count(*),avg(salary),deptId from emp group by deptId; eg:查询所有员工出生的年份 select year(birthday) from emp;(2)子查询多个SQL命令的组合,把一个SQL命令的结果作为另一个命令的条件; eg:查询高于平均工资的男员工 select * from emp where sec=1 && salary>(select avg(salary) from emp); eg:查询和Tom同一年出生的员工 select * from emp where year(birthday)=(select year(birthday) from emp where ename="Tom") && ename!="Tom"; (3)多表查询查询的列分布在不同的表中时,用多表查询(前提:表和表之间必须有关联); eg:查询所有员工的姓名及部门名称 select emp.ename,dept.dname from emp,dept where emp.deptId=dept.did;select ename,dname from emp left outer join dept on deptId=did;
0
0
0
浏览量2014
青椒肉丝加点糖

CSS(六)渐变、高级选择器、弹性布局

一、渐变1. 线性渐变 - linear-gradient( )div { background-image: linear-gradient(color1,color2,……); }渐变最少两个颜色,才能体现出颜色的变化颜色,参数用逗号分开,可以写多种颜色。(1)渐变方向,在颜色前加入角度或关键字控制渐变方向。div { background-image: linear-gradient(-70deg, red, green); }(2)渐变范围格式:background-image: linear-gradient(方向,颜色1 起始值 结束值,颜色 2 起始值 结束值……) div { background-image: linear-gradient(90deg, red 0 40%, green 50% 100%); background-image: linear-gradient(50deg, green 0 110px, yellow 110px 130px, black 130px 190px); }2. 径向渐变 - radial-gradient( )div { background-image: radial-gradient(color1,color2,……); }(1)半径格式:background-image: radial-gradient(半径,颜色1,颜色2);background-image: radial-gradient(x轴半径 y轴半径,颜色1,颜色2); div { background-image: radial-gradient(100px, red 0 30%, green 30% 100%); }当半径只传入一个参数时,表示该渐变形状为圆。(2)圆心起点格式:background-image: radial-gradient(x轴半径 y轴半径 at x轴圆心 y轴圆心,颜色1 起始值 结束值……)在圆心后面增加 at 空格 x轴 y轴 的原点位置,也可使用关键词left/top/bottom/right。div { background-image: radial-gradient(100px at left top, red 0 30%, green 30% 100%); }3. 重复渐变该渐变版本过低的浏览器无法查看效果。4. 渐变的兼容各大浏览器的私有前缀如下:有前缀与无前缀使用区别如下:二、高级选择器1. 属性选择器属性选择器使用 [ ] 将元素属性名称放入其中,通过查找具有该属性的元素来设置样式。(1)简单属性选择器[type=text],[type=password] { width: 600px; } /*选择类型值为text和password的input*/ [class] { color: red; } /*选择所有带有类名的元素*/(2)筛选属性选择器[href^="http"] { /*样式声明;*/ } /*选择href值以"http"开头的元素 ^表示以什么开头,$表示以什么结尾*/ [class*=b] { /*样式声明;*/ } /*选择类名中包含"b"的元素*/ [class~=a] { /*样式声明;*/ } /*选择类名以"a"为独立字段的元素*/2. 目标伪类选择器格式:target{样式声明},对应锚点被激活时,匹配的样式使用a标签href属性连接元素锚点。a~div { width: 200px; height: 100px; display: none; } div:target { /* 被锚点激活的div,也就是目标div */ display: block; } /*表示div隐藏,当点击超链接时显示div*/3. 结构性伪类选择器.myul>li:first-child { /*样式声明;*/ } /*选择ul中的第一个li*/ .box div:last-child { /*样式声明;*/ } /*选择box中的最后一个div*/ .myul>li:nth-child(8) { /*样式声明;*/ } /*选择ul中的第8个li*/ .myul>li:nth-child(odd) { /*样式声明;*/ } /*选择ul中的单数行*/ .myul>li:nth-child(even) { /*样式声明;*/ } /*选择ul中的双数行*/ .myul>:empty { /*样式声明;*/ } /*选择父元素中某个为空的子元素*/ ol>li:only-child { /*样式声明;*/ } /*父元素中只有一个子元素*/ .myul>li:not(.mm) { /*样式声明;*/ } /*选择ul中除类名为mm的li之外的所有元素*/ /*取反选择器,(注意not括号里写整个选择器)*/三、弹性布局   在弹性布局中,父元素无需清除浮动,每个子元素也不用再进行浮动,只需给父元素加 display: flex; 即可。容器控制所有项目的排序,弹性布局必须是容器嵌套项目;复杂嵌套最好不用弹性布局(嵌套层数会过多),使用普通浮动布局即可。1. 基本概念在此布局中,父元素称为"容器",子元素自动成为容器成员,称为"项目"。各自有控制布局的属性,必须是容器包裹着项目。主轴:就是项目的排列方向,主轴会出现四个方向;交叉轴:就是在主轴的垂直方向,项目可在交叉轴上移动。2. 将容器指定为 flex 布局任何一个容器都可以指定为 Flex 布局,设为 Flex 布局以后,子元素的 float、clear 等属性将失效。3. 容器的属性(1)主轴方向 -  flex-direction(3)主轴和换行简写 - flex-flow(4)主轴对齐方式 - justify-content(5)交叉轴对齐方式 - align-items  前提是项目换行,容器的垂直轴方向有独立高度或者宽度。(6)多轴线对齐方式 - align-content如果项目只有一根轴线,该属性不起作用,前提是容器有高度4. 项目属性(1)项目排列数次序 - order  改变原有标签的排序。 数值越小,排列越靠前,默认为0,可以为负值。.box>div:nth-child(2){ order: 1; }(2)项目的放大比例 - flex-grow定义项目的放大比例,默认为0。单行有剩余空间时,项目可以使用放大比例,前提是项目不换行。项目设置放大比例为非默认比例时,原宽度失效。(3)项目的缩小比例 - flex-shrink  项目的缩小比例,默认为 1,负值无效。值为0时,即使压缩,该项目仍然保持自己的原有宽度,其他值如 2、10等,缩小比例值越大,缩小比重就越大。.box>div:nth-child(4) { flex-shrink: 0; } /*压缩时第四个项目不会缩小自己原有宽度,其余缩小*/(4)项目的自动尺寸 - flex-basis可以代替宽度,与宽度表现形式基本一样,当flex-basis和width属性同时存在时,width属性不再生效。(5)项目的简写方式  - flex包含flex-grow(放大比例),flex-shrink(缩小比例) 和 flex-basis(自动尺寸)。常用项目设置:flex: 0 0 *px;  表示不放大、不缩水、所占尺寸大小。
0
0
0
浏览量586
青椒肉丝加点糖

JS 高级(五)ES5新增函数

ES5(ECMAScript 第5个版本)数组中新增函数判断函数every(),专门判断一个数组中是否所有元素都符合要求。 var 判断结果=数组.every( function(当前元素值n,当前下标i,当前数组arr){//回调函数 return 检查当前元素值是否符合要求,并返回检查结果 } );every 内自带 for 循环,自动遍历数组中每个元素,每遍历一个元素,就自动调用一次回调函数;每次调用回调函数时,都自动传入三个值:当前元素值 n、当前下标 i、当前数组对象 arr。如果本次回调函数判断结果为 true,则至少说明当前元素符合要求,every 会自动遍历下一个元素,直到所有元素遍历完成。如果都没有碰到不符合要求的元素,则结束循环,整体返回 true,说明当前数组中所有元素都符合要求。如果本次回调函数判断结果为 false,则说明当前元素不符合要求,every 立刻退出循环,直接返回 false,表明当前数组中不是所有元素都符合要求。举例:判断哪个数组全部由偶数组成;<script> var arr1 = [1, 3, 5, 7, 9]; var arr2 = [2, 4, 6, 6, 4]; var result1 = arr1.every( function (n, i, arr) { console.log(` arr1.every自动调用了一次回调函数; 收到实参值:n=${n}i=${i}arr=${arr}; 回调函数执行结果返回${n%2==0} `); return n % 2 == 0; } ); var result2 = arr2.every( function (n, i, arr) { console.log(` arr2.every自动调用了一次回调函数; 收到实参值:n=${n}i=${i}arr=${arr}; 回调函数执行结果返回${n%2==0} `); return n % 2 == 0; } ); console.log(result1, result2); //false true </script>some(),专门检查一个数组中是否包含符合要求的元素;var 判断结果=数组.some( function(当前元素值, 当前下标位置, 当前数组){ return 判断当前元素值是否符合要求 } )some 内自带 for 循环,自动遍历数组中每个元素,每遍历一个元素,就自动调用一次回调函数;每次调用回调函数时,都自动传入三个值:当前元素值、当前下标 i、当前数组对象 arr,在回调函数内,判断当前元素值是否符合要求,并返回判断结果给some函数。如果本次回调函数判断结果为 true,则说明至少当前元素符合要求,some 立刻退出循环,直接返回 true,说明当前数组中包含至少一个符合要求的元素。如果本次回调函数判断结果为 false,则说明当前元素不符合要求,some 只能继续遍历下一个元素。如果直到遍历结束都没有发现符合要求的元素,则返回 false。说明当前数组中不包含符合要求的元素。举例:判断哪个数组中包含奇数;<script> var arr1 = [1, 3, 5, 7, 9]; var arr2 = [2, 4, 6, 6, 4]; var result1 = arr1.some( function (n, i, arr) { console.log(` arr1.some自动调用了一次回调函数; 收到实参值:n=${n}i=${i}arr=${arr}; 回调函数执行结果返回${n%2==1} `); return n % 2 == 1; } ); var result2 = arr2.some( function (n, i, arr) { console.log(` arr2.some自动调用了一次回调函数; 收到实参值:n=${n}i=${i}arr=${arr}; 回调函数执行结果返回${n%2==1} `); return n % 2 == 1; } ); console.log(result1, result2); //true false </script>遍历函数forEach(),专门遍历函数代替 for 循环来简化遍历索引数组的特殊函数;数组.forEach(function(当前元素值, 当前下标i, 当前数组){ 对当前元素值执行操作 })在回调函数内,对当前元素执行规定的操作,不需要返回值。举例:点名;<script> var arr = ["汤米", "鲍勃", "朱丽叶", "巴啦啦"]; // for循环遍历写法 for (i = 0; i < arr.length; i++) { console.log(`${arr[i]} - 到!`); } // forEach写法 arr.forEach(function (n) { console.log(`${n} - 到!`); }) // forEach简写 arr.forEach(n => console.log(`${n} - 到!`)) </script>map(),专门读取原数组中每个元素值,进行修改后,生成一个新数组返回,格式如下:var 新数组=原数组.map( function(当前元素值, 当前下标i, 当前数组){ return 当前元素值修改后的新值 } )在回调函数内,对当前元素值进行修改,并将修改后的新值返回给map函数;map函数接到新值后,自动放入新数组中对应的位置;遍历结束,map返回新数组。原数组保持不变。举例:将数组中所有元素*2,返回新数组;<script> var arr1 = [1, 2, 3, 4, 5, 6, 7]; var arr2 = arr1.map( function (n, i) { return n * 2; } ) console.log(arr1);//[1, 2, 3, 4, 5, 6, 7] console.log(arr2);//[2, 4, 6, 8, 10, 12, 14] </script>Filter(),过滤,复制出数组中符合要求的个别元素,放入新数组中返回。格式如下:var 新数组=数组.filter( function(当前元素值, 当前下标i, 当前数组){ return 判断当前元素值是否符合要求 } )在回调函数内,判断当前元素值是否符合要求,并返回判断结果,如果当前元素的判断结果为 true,说明当前元素符合条件,则 filter 会将当前元素追加到新数组中保存,如果当前元素的判断结果为 false,说明当前元素不符合要求,则 filter 什么也不干,继续遍历下一个元素。举例:过滤出数组中的偶数;<script> var arr1 = [1, 2, 3, 4, 5, 6]; var arr2 = arr1.filter( function (n, i) { console.log(`arr.filter()自动调用一次回调函数。接收到元素值=${n}。判断后结果为${n%2==0}`); return n % 2 == 0 } ) console.log(arr1);//[1, 2, 3, 4, 5, 6] console.log(arr2);//[2, 4, 6] </script>数组汇总 reduce(),汇总,对数组中所有元素进行统计,并返回统计结果的函数;var 结果=数组.reduce( function(捐款箱, 当前元素值n, 当前下标i, 当前数组arr){ return捐款箱+当前元素值 }, 起始值 )reduce 先在内部创建一个变量,保存汇总的起始值(捐款箱变量);自带 for 循环,自动遍历原数组中每个元素,每遍历一个元素,就自动调用一次回调函数,每次调用回调函数时,都自动传入4个值:捐款箱变量中的临时汇总值、当前元素值 n、当前下标 i、当前数组对象 arr。在回调函数内,将临时汇总值与当前元素值相加,算出新的汇总值,再返回给 reduce,reduce 拿到新的汇总值之后,放回捐款箱变量中暂存,为继续累加下一个值做准备。举例:对数组内容求和;<script> var arr = [1, 2, 3, 4, 5, 6, 7]; var result = arr.reduce( function (box, n) { console.log(` arr.reduce自动调用一次回调函数, 初始值为:${box}, 当前元素值为:${n}, 返回值:${box + n} `); return box + n; }, 0 //起始值 ) console.log(result); //28 </script>补充:this 5种(1)obj.fun()  fun中的this指 .前的obj对象(谁调用指谁);(2)new Fun()  Fun中的this指new创建的新对象;(3)fun() 或 (function(){ ... })() 或 回调函数 thisz默认指windozw;(4)原型对象(prototype)中的this指将来调用这个共有函数的.前的某个子对象(谁调用指谁);(5)访问器属性中的this指代访问器属性所在的当前对象。
0
0
0
浏览量1169
青椒肉丝加点糖

H5画布 canvas(二)绘制文字、图片、坐标系,canvas颜色和样式,canvas绘制环境

1. 绘制文字ctx.font;设置文本内容的字体属性,使用方式与 css font 相同ctx.textAlign;设置文本内容的对齐方式       start:默认,文本在指定的位置开始       end:文本在指定的位置结束       center:文本的中心被放置在指定的位置       left:文本左对齐       right:文本右对齐ctx.textBaseline;设置绘制文本时使用的当前文本基线      alphabetic:默认,文本基线是普通的字母基线      top:文本基线是 em 方框的顶端      hanging:文本基线是悬挂基线      middle:文本基线是 em 方框的正中心      ideographic:文本基线是 em 基线      bottom:文本基线是 em 方框的底端ctx.fillText();填充文本ctx.strokeText();绘制文本(无填充)ctx.measureText();返回包含指定文本宽度的对象接下来我们在上文饼状图案例的基础上绘制文字:<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>绘制饼状图&文字</title> <style></style> </head> <body> <div> <canvas id="table"></canvas> </div> </body> <script> var canvas = document.getElementById('table'); //获取canvas标签 var ctx = canvas.getContext('2d'); //获取上下文 //设置画布宽高、边框(边框也可使用CSS选择器来设定) canvas.width = 600; canvas.height = 400; canvas.style.border = '2px solid #000'; //定义饼状图数据 var data = [{ 'value': 0.2, 'color': '#149985', 'title': '城市A' }, { 'value': 0.3, 'color': 'red', 'title': '城市B' }, { 'value': 0.4, 'color': 'blue', 'title': '城市C' }, { 'value': 0.1, 'color': '#999999', 'title': '城市D' }, ] //绘制饼状图 var tempAngle = -90; //记录绘制到了哪个角度 for (var i = 0; i < data.length; i++) { ctx.beginPath(); //每一次循环都绘制不同的扇区,所以都要开启新状态 ctx.moveTo(200, 200); //每一次都回到圆心点开始绘制 var angle = data[i].value * 360; //每一个扇区的角度 ctx.fillStyle = data[i].color; //颜色填充按照数据遍历 var startAngle = tempAngle * Math.PI / 180; //起始角度 var endAngle = (tempAngle + angle) * Math.PI / 180; //每一次的结束角度=起始角度+扇区角度 ctx.arc(200, 200, 100, startAngle, endAngle); //绘制文字 var txt = data[i].value * 100 + '%'; //获取要绘制的文字 var x, y; //文字坐标 var txtAngle = tempAngle + 1 / 2 * angle; //文字位置的角度 = 起始角度 + 扇区的一半 //计算文字坐标 x = 200 + Math.cos(txtAngle * Math.PI / 180) * (100 + 20); y = 200 + Math.sin(txtAngle * Math.PI / 180) * (100 + 20); ctx.font = '20px "微软雅黑"'; //设置字体 if (txtAngle > 90 && txtAngle < 270) { //设置y轴左边的文字结束位置对齐,防止文字显示不全 ctx.textAlign = 'end'; } ctx.fillText(txt, x, y); //填充文字 ctx.fill(); tempAngle = tempAngle + angle; //每次绘制完一次扇区起始角度为原角度加该扇区角度 } </script> </html>加上文字的饼状图如下:在这里注意我们计算文字文字位置时用到了两个公式:200 为圆心点的位置,cos 计算 x 轴方向的位置,sin 计算 y 轴方向的位置,100 为半径长度,20 是文字到圆周的距离;该公式通用。x = 200 + Math.cos(txtAngle * Math.PI / 180) * (100 + 20); y = 200 + Math.sin(txtAngle * Math.PI / 180) * (100 + 20);2. 绘制图片(drawImage)(1)基本绘制方法ctx.drawImage(img,x,y);绘制图片基本方式,x y 为绘片左上角的坐标, img是绘制图片的dom对象ctx.drawImage(img,x,y,width,height);绘制图片并规定宽高ctx.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);绘制图片并在画布上定位被裁剪的部分,sx,sy 裁剪区域的左上角坐标, swidth 裁剪图片的宽度,sheight 裁剪的高度,其余属性相同如下简单案例:(2)案例:序列帧动画(通过图片裁剪,实现人走路的动态效果)        图片裁剪常用育在一张具有多种元素的图片中裁剪出其中一个元素,例如在一张具有多个人物的图片中抠出其中一个人物等等。接下来我们通过一张人走路的序列帧图来实现动态效果;原始序列帧图片如下:过程也很简单,就是使用到了循环计时器 setInterval,循环裁剪图片中的每一帧,并清除之前裁剪的所有元素,只展示最新的元素,实现动态效果。<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>序列帧动画</title> <style></style> </head> <body> <div> <canvas id="table"></canvas> </div> </body> <script> var canvas = document.getElementById('table'); //获取canvas标签 var ctx = canvas.getContext('2d'); //获取上下文 //设置画布宽高、边框(边框也可使用CSS选择器来设定) canvas.width = 600; canvas.height = 400; canvas.style.border = '2px solid #000'; //绘制图片 var img = new Image(); //创建图片DOM对象 img.src = 'img/zoulu.jpg'; //图片路径,设置后img对象会立即加载图片 img.onload = function () { var framIndex = 0; setInterval(function () { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, framIndex * 80, 0, 50, 400, 200, 100, 80, 300); //绘制图片 framIndex++; //添加到下一帧 framIndex %= 5; }, 1000 / 6); } </script> </html>案例效果如下:3. 绘制坐标系<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>绘制坐标系</title> <style></style> </head> <body> <div> <canvas id="table"></canvas> </div> </body> <script> var canvas = document.getElementById('table'); //获取canvas标签 var ctx = canvas.getContext('2d'); //获取上下文 //设置画布宽高、边框(边框也可使用CSS选择器来设定) canvas.width = 600; canvas.height = 400; canvas.style.border = '2px solid #000'; //画笔起点 var x0 = 100; var y0 = 380; var maxHeight = 390; var arrowWidth = 10; //箭头宽度 //绘制x轴 ctx.beginPath(); ctx.strokeStyle = 'blue'; ctx.moveTo(x0, y0); ctx.lineTo(500, 380); ctx.lineTo(500 - arrowWidth, 380 - arrowWidth); ctx.moveTo(500, 380); ctx.lineTo(500 - arrowWidth, 380 + arrowWidth); ctx.stroke(); //绘制y轴 ctx.beginPath(); ctx.moveTo(x0, y0); ctx.lineTo(100, 0); ctx.lineTo(100 - arrowWidth, arrowWidth); ctx.moveTo(100, 0); ctx.lineTo(100 + arrowWidth, arrowWidth); ctx.stroke(); //绘制线段 var data = [0.4, 0.5, 0.3, 0.8, 0.4, 0.6]; //假数据 var pointWidth = 380 / (data.length + 1); ctx.beginPath(); ctx.strokeStyle = 'red'; for (var i = 0; i < data.length; i++) { var x = x0 + (i + 1) * pointWidth; var y = y0 - data[i] * maxHeight; ctx.lineTo(x, y) } ctx.stroke(); </script> </html>效果如下:4. canvas 颜色样式和阴影(了解)相关颜色样式:ctx.fillStyle;填充颜色(可支持所有格式的颜色)ctx.strokeStyle;描边颜色(可支持所有格式的颜色)ctx.strokeStyle = 'red'; ctx.strokeStyle = '#ccc'; ctx.strokeStyle = 'rgb(255,0,0)'; ctx.strokeStyle = 'rgba(255,0,0,6)';相关阴影样式(效率低、性能差,建议不使用):ctx.shadowColor;阴影颜色ctx.shadowBlur;模糊级别,大于 1 的正整数,数值越高,模糊程度越大ctx.shadowOffsetX;阴影距形状的水平距离ctx.shadowOffsetY;阴影距形状的垂直距离使用方式与 css 中类似:ctx.shadowColor = 'teal'; ctx.shadowBlur = 10; ctx.shadowOffsetX = 10; ctx.shadowOffsetY = 10; ctx.fillRect(100, 100, 100, 100);5. 复杂样式(1)渐变ctx.createLinearGradient(x0,y0,x1,y1);线性渐变,x0 y0 为起始坐标,x1 y1 为结束坐标,使用时需要添加渐变色var grd = ctx.createLinearGradient(0, 0, 170, 0); grd.addColorStop(0, 'black'); //添加一个渐变颜色,值介于 0.0 与 1.0 之间 grd.addColorStop(1, 'white'); //添加一个渐变颜色 ctx.fillStyle = grd; //把渐变设置到填充的样式ctx.createRadialGradient(x0,y0,r0,x1,y1,r1);圆形渐变,x0 渐变开始圆的 x 坐标,y0 渐变的开始圆的 y 坐标,r0: 开始圆的半径,x1 渐变的结束圆的 x 坐标,y1 渐变的结束圆的 y 坐标,r1 结束圆的半径var rlg = ctx.createRadialGradient(300, 300, 10, 300, 300, 200); rlg.addColorStop(0, 'teal'); //添加一个渐变颜色 rlg.addColorStop(0.4, 'navy'); rlg.addColorStop(1, 'purple'); ctx.fillStyle = rlg; //设置 填充样式为延续渐变的样式 ctx.fillRect(100, 100, 500, 500);(2)绘制背景图ctx.createPattern(img,repeat);img 设置平铺背景的图片,repeat 背景平铺的方式var ctx = c.getContext('2d');var img = document.getElementById('lamp');var pat = ctx.createPattern(img, 'repeat');ctx.rect(0, 0, 150, 100);ctx.fillStyle = pat; //  把背景图设置给填充的样式ctx.fill();(3)变换(重点)ctx.scale(scalewidth,scaleheight);画布缩放ctx.translate(x,y);位移画布,发生位移后,相当于把画布的 0,0 坐标更换到新的 x,y 位置,所有绘制的新元素都被影响ctx.rotate(angle);旋转画布6. 绘制环境的相关操作ctx.save();保存当前环境的状态,可以把当前绘制环境进行保存到缓存中ctx.restore();返回之前保存过的路径状态和属性ctx.globalAlpha=number;设置绘制环境的透明度,值介于0-1之间ctx.clip();在画布的限定区域绘制,从原始画布中剪切任意形状和尺寸,一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内canvas.toDataURL(type, encoderOptions);把 canvas 绘制的内容输出成 base64 内容,type 设置输出的类型,比如 image/png image/jpeg 等;encoderOptions 值为 0-1 之间的数字,用于标识输出图片的质量,1 表示无损压缩var canvas = document.getElementById("canvas"); var dataURL = canvas.toDataURL(); console.log(dataURL); var img = document.querySelector("#img-demo");//拿到图片的dom对象 img.src = canvas.toDataURL("image/png"); //将画布的内容给图片标签显示
0
0
0
浏览量1820
青椒肉丝加点糖

DOM(三)修改元素属性、样式、添加/删除元素

一、DOM修改元素1. 修改属性(1)字符串类型的 HTML 标准属性(上篇)(2)bool 类型的 HTML 标准属性(上篇)(3)自定义扩展属性        HTML 标准中没有规定,程序员根据自身的需要自发添加的属性就是自定义属性。a:自定义属性经常用于代替 id、class 或元素选择器,作为查找触发事件的元素的条件;CSS 的各种选择器均有不足之处:i. id 选择器,只能选1个; ii. class 选择器,本职工作是定义样式,而样式的修改极其频繁!如果用class选择器查找元素绑定事件,一旦样式类发生变化,程序必然出错; iii. 元素选择器,因为实现同一种效果,可选的标签名优很多,没有统一规定。如果用元素选择器查找触发事件的元素,绑定事件,则元素一改,功能又立刻出错。        为了解决以上问题,就可以为元素添加自定义属性,当查找触发事件的元素时,用属性选择器[自定义属性]来查找即可。b:在 js 中访问自定义扩展属性        要注意自定义属性不能用 . 访问,因为自定义属性是后天程序员自发添加的,在 HTML 标准中没有规定。所有在内存中的元素对象上,不包含自定义扩展属性!可以用旧核心DOM:元素.getAttribute("自定义属性名") 元素.setAttribute("自定义属性名", "属性值")        在新版的HTML5标准中,有新的规定:        ① HTML 中,所有自定义属性名必须以 data- 开头:<元素   data-自定义属性名="属性值">        ② 如果在 html 中以 data- 开头了,则 js 中: 元素.dataset.自定义属性名。举例:点击按钮,记录次数;<body> <button data-n="0" data-btn>click me</button> <script> //想点按钮,给n属性的值+1 //DOM 4步 //1. 查找触发事件的元素 // 本例中: 查找带有data-btn属性的一个按钮 var btn = document.querySelector("[data-btn]"); //2. 绑定事件处理函数 btn.onclick = function () { //3. 查找要修改的元素 //4. 修改元素 //4.1 获取自己身上data-n属性中保存的旧点击次数,转为整数 var n = parseInt( this.getAttribute("data-n") ); //4.2 次数+1 n++; //4.3 再放回去 this.setAttribute("data-n", n); } </script> </body>2. 修改样式(1)修改内联样式格式:元素.style.css属性="属性值"由于有些 css 属性名中带-,这样会和减法的 - 号冲突;所以所有带 - 的 css 属性名必须去掉 - 变驼峰命名,比如:font-size ->  fontSize、background-color -> backgroundColor、list-style-type -> listStyeType。(2)获取样式        使用元素 .style.css 属性的方式,只能获取内联样式,无法获得内部或外部样式表中层叠或继承来的 css 属性值。所以今后要想获得元素任意 css 属性值,都要获得计算后的样式。计算后的样式就是最终应用到一个元素上的所有 css 属性的总和。获取方法分为两步:i. 先获得计算后的样式对象:var style=getComputedStyle(元素对象); ii. 从完整的样式对象中只提取个别css属性:style.css属性;举例:获取 h1 元素计算后的样式;<body> <h1 id="h1" style="color:yellow">Welcome</h1> <p>Welcome to my web site</p> <script> var h1 = document.getElementById("h1"); //用style,获得字体颜色,背景颜色,字体大小 console.log(h1.style.color); console.log(h1.style.backgroundColor); console.log(h1.style.fontSize); //用计算后的样式,获得字体颜色,背景颜色,字体大小 var style = getComputedStyle(h1); console.log(style.color); console.log(style.backgroundColor); console.log(style.fontSize); </script> </body>        在实际的项目中,很多效果都需要批量修改一个元素的多个 css 属性,而 .style 一句话只能修改一个 css 属性,如果修改多个 css 属性时代码会很繁琐;所以只要批量设置一个元素的多个 css 属性,都用 class 代替 .style。二、添加/删除元素1. 添加一个新元素(1)创建一个新的空元素对象:var 新元素对象=document.createElement("标签名") //eg: var a=document.createElement("a");//<a></a>(2)为新元素添加必要属性:元素对象.属性名=新值 //eg: a.innerHTML="go to tmooc"; a.href="http://tmooc.cn"; //<a href=" http://tmooc.cn "> go to tmooc </a> (3)将新元素添加到 DOM 树的指定父元素下://在父元素下末尾追加新元素 父元素.appendChild(新元素) //在父元素下插入到一个现有子元素之前 父元素.insertBefore(新元素,现有子元素) //替换父元素下的一个现有的子元素 父元素.replaceChild(新元素,现有子元素)举例:创建一个a元素和一个文本框;<body> <script> //向页面中添加一个a // 1.创建一个空元素 var a = document.createElement("a"); // 2.为新元素添加必要属性 a.innerHTML = "进入百度官网"; a.href = "www.baidu.com"; // 3.将新元素添加到DOM树 document.body.appendChild(a); //再创建普通的文本框 var input = document.createElement("input"); //将文本框放在a的后边? document.body.appendChild(input) //将文本框放在a的前边? //document.body.insertBefore(input, a); //用文本框替换a? //document.body.replaceChild(input,a); </script> </body>2. 优化        修改 DOM 树的内容会导致重排重绘,但频繁重排重绘会降低页面加载的效率,如果父元素已经在页面上了,要添加多个平级子元素,就要借助于文档片段对象来实现。        文档片段是指内存中临时保存多个平级子元素的虚拟父元素,使用方法:(1)先创建文档片段对象: var 文档片段对象=document.createDocumentFragment();(2)将子元素先添加到文档片段对象中文档片段对象.appendChild(子元素)(3)将文档片段对象一次性添加到页面上父元素.appendChild(文档片段对象);3. 删除元素父元素.removeChild(子元素)举例:动态生成表格;<head> <title>动态创建表格</title> <meta charset="utf-8" /> <style> table { width: 600px; border-collapse: collapse; text-align: center; } td, th { border: 1px solid #ccc } </style> </head> <body> <div id="data"> <table> <thead> <tr> <th>姓名</th> <th>薪资</th> <th>年龄</th> <th>删除</th> </tr> </thead> </table> </div> <script> var json = [{ "ename": "Tom", "salary": 11000, "age": 25 }, { "ename": "John", "salary": 13000, "age": 28 }, { "ename": "Mary", "salary": 12000, "age": 25 } ]; //1. 先创建一个tbody var tbody = document.createElement("tbody"); //2. 再遍历json数组中每个员工对象 for (var emp of json) { //每遍历一个员工对象,就创建一个tr,追加到tbody中 var tr = document.createElement("tr"); tbody.appendChild(tr); //3. 遍历当前员工对象中每个属性值 for (var key in emp) { //每遍历一个属性值,就创建一个td,追加到tr中。并设置当前td的内容为当前属性的属性值 var td = document.createElement("td"); tr.appendChild(td); td.innerHTML = emp[key]; } //说明当前行的属性值td已经添加完成 //就可以为当前行中再多添加一个td var td = document.createElement("td"); tr.appendChild(td); //创建button,放入td中 var btn = document.createElement("button"); btn.innerHTML = "删除"; td.appendChild(btn); // 为当前按钮绑定单击事件 btn.onclick = function () { // 点哪个按钮,就让哪个删除 // 查找tbody var tbody = document.querySelector("#data>table>tbody"); // 获得当前点击的删除按钮 var str = this.parentElement.parentElement; // 获得员工姓名当前tr下的第一个td var ename = tr.childNodes[0].innerHTML; // 先确认,再删除 var result = confirm(`是否继续删除${ename}`); if (result == true) { tbody.removeChild(tr); } } } //3. 整个遍历结束后,再将tbody一次性追加到table中 var table = document.querySelector("#data>table"); table.appendChild(tbody); </script> </body>
0
0
0
浏览量962

履历