@each 指令一般用来循环一个列表或 Map ,它的写法是这样的 @each in { … } ,这其中 expression 表达式返回一个列表或者直接就是一个列表,variable 是列表中的每一项,{} 中是每次循环都会执行的代码,我们举例来看下:$borders: 2px, 3px, 5px;@each $bor in $borders { .border-#{$bor} { border:$bor solid; }}上面的代码中我们通过 @each 循环一个 $borders 列表,来生成不同的 class 的 border 样式,上面这段代码转换为 CSS 如下:.border-2px { border: 2px solid;}.border-3px { border: 3px solid;}.border-5px { border: 5px solid;}可以看到上面的写法是不是很方便,这样就直接生成了不用的类名并且对应不同的样式,在 Sass 编程中 @each 也是很常用的指令,所以这个你是一定要会用的,尤其是在写函数的时候!
// 服务端现有接口,进行 post 请求Ajax({ method: 'post', url: '/simple/post', data: { a:1, b:2 }}).then(data => { console.log(data)}).catch(e => { console.log('/simple/post', e)})// 服务端暂时没有的接口, 进行 post 请求Ajax({ method: 'post', url: '/test/post', data: { a:1, b:2 }}).then(data => { console.log(data)}).catch(e => { console.log('/test/post', e)})// 服务端现有接口, 进行 get 请求Ajax({ url: '/simple/get', params: { c:1, d:2 }}).then(data => { console.log(data)}).catch(e => { console.log('/simple/get', e)})
Ruby 的每个迭代器都从哈希和数组中返回每个元素,最常见的是 each 迭代器。下面是一个数组的例子。实例:[1, 2, 3, 4, 5].each do |number| puts numberend# ---- 输出结果 ----12345解释:number 参数代表着每次迭代器循环的每个元素,一共循环 5 次,分别输出 1,2,3,4,5。上面的场景同样适用于哈希:实例:{a: 1, b: 2, c: 3}.each do |item| puts "======" puts item puts item.class puts "======"end# ---- 输出结果 ----======a1Array============b2Array============c3Array======解释:通过上述例子我们可以看到,我们在每次迭代出来的元素是一个Array,第一个元素是每个键值对的键,第二个元素是每个键值对的值。
each 可以把数组每个元素作为参数执行操作,但返回值仍是数组本身。实例:a = [1,2,3,4,5,6,7,8,9,10].each {|e| puts e.to_s + '!'}puts a.to_s# ---- 输出结果 ----1!2!3!4!5!6!7!8!9!10![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ajax 是前端用于发送接口请求的技术,它是异步的,需要等待结果返回后执行在发送 ajax 请求时,我们可能会这样去写。ajax({ url: '', method: '', data: {}, params: {}, success: function (res) {}, error: function (err) {}})url: 接口请求地址;method: 接口请求方法,如:get、post 等;data: 请求时使用 body 传输的数据,一般用于 post 请求中;params: 请求时使用 url 传递的数据,一般用于 get 请求中;success: 接口请求成功时的回调,参数为接口成功的返回值;error: 接口请求失败时的回调,参数为抛出异常时的调用栈等信息。XMLHttpRequest 是浏览器提供的对象,用于进行后台与服务端的数据进行交互
<?phpnamespace app\study\controller;use app\study\model\StudentModel;use cmf\controller\AdminBaseController;use PhpOffice\PhpSpreadsheet\Spreadsheet;use PhpOffice\PhpSpreadsheet\Writer\Xlsx;use think\facade\Request;class StudentController extends AdminBaseController{ public function add() { return $this->fetch(); } public function addPost() { try { $studentModel = new StudentModel(); $studentModel->name = $this->request->param('name', ""); $studentModel->age = $this->request->param('age', 0, 'intval'); $studentModel->id_number = $this->request->param('id_number', ""); $studentModel->created_at = time(); $studentModel->save(); } catch (\Exception $exception) { return $this->error($exception->getMessage()); } return $this->success('请求成功'); } public function upload() { return $this->fetch(); } public function uploadExcel() { $data = $this->request->param(); $file_url = "./upload/" . $data['file_url']; $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_url); $n = 2; while (true) { $name = $spreadsheet->getActiveSheet()->getCell('A' . $n)->getValue(); $age = $spreadsheet->getActiveSheet()->getCell('B' . $n)->getValue(); $id_number = $spreadsheet->getActiveSheet()->getCell('C' . $n)->getValue(); try { $studentModel = new StudentModel(); $studentModel->name = $name; $studentModel->age = $age; $studentModel->id_number = $id_number; $studentModel->created_at = time(); $studentModel->save(); } catch (\Exception $exception) { } if (empty($name) && empty($age) && empty($id_number)) { break; } $n++; } return $this->success('导入成功'); } public function down() { //读取数据 $students = StudentModel::select(); //设置 excel 信息 $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->getDefaultRowDimension()->setRowHeight(20);//设置默认行高 $sheet->getDefaultColumnDimension()->setWidth(10);//设置默认宽度 $sheet->getStyle("A1:Z1")->getFont()->setSize(10)->setBold(true);//设置第一行字体 $sheet->getStyle("A1:Z1")->getFont()->getColor()->setRGB("FFFFFF");//设置第一行字体颜色 $sheet->setCellValue('A1', 'ID'); $sheet->setCellValue('B1', '学生姓名'); $sheet->setCellValue('C1', '年龄'); $sheet->setCellValue('D1', '身份证号'); $n = 2; foreach ($students as $student) { $sheet->setCellValue('A' . $n, $student->id);//客户名称 $sheet->setCellValue('B' . $n, $student->name);//客户编号 $sheet->setCellValue('C' . $n, $student->age);// $sheet->setCellValue('D' . $n, $student->id_number); $n++; } $file = "学生信息" . date('YmdHis') . ".xlsx"; $writer = new Xlsx($spreadsheet); header('Content-Disposition: attachment;filename=' . $file);//告诉浏览器将输出文件的名称 header('Cache-Control: max-age=0');//禁止缓存 $writer->save("php://output");; }}
接下来讲到的一种是服务端代理的方式。要问为什么采取服务端代理的方式呢?很简单,因为浏览器端 Ajax 请求有跨域的限制,那我们就把请求不同域的操作放在服务端好了,毕竟服务端是没有跨域限制这一说的。3.2.1 服务端代理原理浏览器端发送请求到同域的服务端;服务端接收到请求之后,进行转发,请求不同域的另外一个服务端;服务端间进行交互数据后,同域服务端返回数据给浏览器端。3.2.2 具体例子举一个服务端代理的例子,这里我使用了一个 Express 的中间件,叫做 express-http-proxy 。当然同学们也可以在同域服务端接收到请求的时候,发起 http 请求访问不同域的服务端来模拟这一代理行为。前端方面我使用了 jQuery 的 Ajax 方法。3.2.2.1 javaScript 关键代码$.ajax({ url: '/proxy/proxy_get', method: 'GET', data: { a: '123', b: '234' }}).done(data => { console.log(data)})很简单,我们就是向同域的服务器发送了一个请求。3.2.2.2 同域服务器关键代码const proxy = require('express-http-proxy'); // 引入代理中间件// ... 一些代码app.use('/proxy', proxy('http://localhost:8082/')); // 注册,之后 /proxy 都会代理到 http://localhost:8082/ 上3.2.2.3 不同域的服务器关键代码router.get("/proxy_get", function(req, res) { const {a, b} = req.query res.send(`参数是:${a} 和 ${b}`)});这是目标服务器的响应方法,返回一个 处理后的字符串。3.2.2.4 效果3.2.3 服务端代理小结服务端代理通过服务端和服务端之间的交互来避免浏览器和不同域的服务端之间直接进行交互,从而避免了跨域的问题。当然这种方法要求我们有一个中间服务器的存在。
相信大家不管是 Android 开发还是 Java 服务端开发都使用 JavaBean 或者 Model 类,我们经常会借助 IDEA 工具来自动生成构造器函数和 setter,getter 函数。但是可曾想过如果没有 IDEA 工具来生成代码,需要很多 model 类模板代码可是会花蛮久时间的。那么一起来看下 Kotlin 的 data class 如何替代 Java 中 Model 类的。在 Java 实现一个 Movie 类:package com.imooc.imooctest.model;public class Movie { private String title; private String year; private String type; private String poster; private String rated; private String released; private String runtime; private String genre; private String director; private String writer; private String actors; private String language; public Movie(String title, String year, String type, String poster, String rated, String released, String runtime, String genre, String director, String writer, String actors, String language) { this.title = title; this.year = year; this.type = type; this.poster = poster; this.rated = rated; this.released = released; this.runtime = runtime; this.genre = genre; this.director = director; this.writer = writer; this.actors = actors; this.language = language; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getYear() { return year; } public void setYear(String year) { this.year = year; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getPoster() { return poster; } public void setPoster(String poster) { this.poster = poster; } public String getRated() { return rated; } public void setRated(String rated) { this.rated = rated; } public String getReleased() { return released; } public void setReleased(String released) { this.released = released; } public String getRuntime() { return runtime; } public void setRuntime(String runtime) { this.runtime = runtime; } public String getGenre() { return genre; } public void setGenre(String genre) { this.genre = genre; } public String getDirector() { return director; } public void setDirector(String director) { this.director = director; } public String getWriter() { return writer; } public void setWriter(String writer) { this.writer = writer; } public String getActors() { return actors; } public void setActors(String actors) { this.actors = actors; } public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; }}使用 Kotlin 的 data class 实现一个 Movie 类:data class MovieEntity( val title: String, val year: String, val type: String, val poster: String, val rated: String, val released: String, val runtime: String, val genre: String, val director: String, val writer: String, val actors: String)可以看到比较大差距的对比,仅仅需要十几行代码就能替代百来行的 Java 模板代码,可以说使用 Kotlin 实现和 Java 同样功能,代码量可以下降很多的。
根据一个类型的数据得到另一个类型的数据,换言之,根据输入得到输出。Function 接口有一个抽象方法 apply 和默认方法 andThen,通过 andThen 可以把多个 Function 接口进行组合,是适用范围最广的函数接口。1272结果如下:30220上述四个函数接口是最基本最常用的函数接口,需要熟悉其相应的使用场景并能够熟练使用。 UnaryOperator 和 BinaryOperator 作用与 Funciton 类似,大家可以通过 Java 的源代码进一步了解其作用。
因为 .send() 是无法支持 Json 格式数据的,所以我们需要对 data 做一个序列化处理:/** * 处理 data,因为 send 无法直接接受 json 格式数据,这里我们可以直接序列化之后再传给服务端 * @param {*} data */function transformData (data) { if (isPlainObject(data)) { return JSON.stringify(data) } return data}实现非常简单,如果判断 data 是一个纯对象的话,就加一道 JSON.stringify(data) 的操作进行序列化, 否则直接返回 data 本身。
有求也要有应。服务端也需要在前端发出请求的时候做出相应的响应。4.4.1 使用 nodeconst express = require("express");const mysql = require('mysql');const bodyParser = require("body-parser");const router = express.Router(); // express 路由const app = express();// 使用 bodyParser 中间件app.use(bodyParser.json());app.use(bodyParser.urlencoded({ extended: true }));registerRouter(); // 路由注册执行app.use(router); // 使用 router/** * 构建返回结果 * @param {*} code * @param {*} data * @param {*} error */const buildResponse = (code, data = {}, error = null) => { return { code, data, error }}// 创建 mysql 链接, 本地数据库为 mkconst connection = mysql.createConnection({ host : 'localhost', user : 'root', password : 'ok36369ok', database : 'mk'});connection.connect();// 端口号const port = process.env.PORT || 8080;// 监听module.exports = app.listen(port, () => { console.log(`Server listening on http://localhost:${port}, Ctrl+C to stop`);});/***********路由注册模块*************//***路由注册函数*/function registerRouter() { // 查询课程 router.get("/course/get", function(req, res) { connection.query('SELECT id, name, teacher, start_time as startTime, end_time as endTime from course', function (error, results, fields) { if (error) throw error; const responseData = buildResponse(0, {items: results}) // mysql 查询结果包装后进行返回 res.send(responseData); // send 结果 }); }); // other router ..}如上所示,我们引入了 Express 框架、bodyParser 以及 mysql 相关的库。其中, bodyParser 可以解析请求中 body 的内容。 不过我们的重点应该是最下面的函数 registerRouter,这个函数是用来注册我们所有的路由的。我们之后的路由也都会写在这个函数里面。好了,回归正题。为了使服务端响应前端的请求,我们在上面的代码中注册了一个路由: router.get("/course/get", callback)如果前端发送请求到 “/course/get” ,那服务端会触发回调函数 callback,对应到上面代码中,我们可以看到:内部会执行一个查询所有课程的 sql 语句;将查询后的数据进行包装,变为 {code: 0, data: xxx, error: xxxx} 这样的格式;返回数据。相同的,我们也可以使用 java 来实现后端的逻辑。4.4.2 使用 Javapackage com.demo;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;import java.sql.*;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;@WebServlet("/course/get")public class HelloWorld extends HttpServlet { // JDBC 驱动名 static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; // 数据库 URL static final String DB_URL = "jdbc:mysql://localhost:3306/mk?useUnicode=true&useJDBCCompliantTimezoneShift\n" + "=true&useLegacyDatetimeCode=false&serverTimezone=UTC"; // 数据库的用户名 static final String USER = "root"; // 数据库的密码 static final String PW = "ok36369ok"; /** * 包装返回结果 */ private Map buildResponse(int code, Object data, String error) { Map<String, Object> res = new HashMap<String, Object>(); res.put("code", code); res.put("data", data); res.put("error", error); return res; } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } // 获取课程使用 GET, 会进入 doGet protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Connection conn = null; Statement stmt = null; // 设置编码格式 request.setCharacterEncoding("utf-8"); response.setContentType("text/json; charset=utf-8"); PrintWriter out = response.getWriter(); Map<String,Object> resMap = new HashMap<String,Object>(); // 返回结果, Map 类型 try{ // 注册 JDBC 驱动 Class.forName(JDBC_DRIVER); // 打开链接 System.out.println("连接数据库..."); conn = DriverManager.getConnection(DB_URL,USER,PW); // 执行查询 System.out.println(" 实例化Statement对象..."); stmt = conn.createStatement(); String sql; sql = "SELECT * FROM course"; ResultSet rs = stmt.executeQuery(sql); List<Map> Courses = new ArrayList<Map>(); // 展开结果集数据库 while(rs.next()){ // 通过字段检索 Map<String,Object> map = new HashMap<String, Object>(); int id = rs.getInt("id"); String name = rs.getString("name"); String teacher = rs.getString("teacher"); Date startTime = rs.getDate("start_time"); Date endTime = rs.getDate("end_time"); // 分别将 mysql 查询结果 put 到 map中 map.put("id", id); map.put("name", name); map.put("teacher", teacher); map.put("startTime", startTime); map.put("endTime", endTime); Courses.add(map); } Map<String, List> data = new HashMap<String, List>(); // 定义返回数据的 data部分, Map 类型 data.put("items", Courses); // data 添加 items, items 就是我们要的课程列表数据 // 构建输出数据 resMap = buildResponse(0, data, null); // 完成后关闭 rs.close(); stmt.close(); conn.close(); }catch(SQLException se){ // 处理 JDBC 错误 se.printStackTrace(); }catch(Exception e){ // 处理 Class.forName 错误 e.printStackTrace(); }finally{ // 关闭资源 try{ if(stmt!=null) stmt.close(); }catch(SQLException se2){ } try{ if(conn!=null) conn.close(); }catch(SQLException se){ se.printStackTrace(); } } String responseData = JSON.toJSONString(resMap);// 将 Map 类型的结果序列化为 String out.println(responseData); // 返回结果 }}这里主要使用的是 servlet 的方式来为前端提供服务,对于请求课程列表来说,使用到 GET 方法,因此本例子中会进入到 doGet 方法中。另外,所用到的技术在章节须知中也有讲到,这里就不再累赘。实现的代码虽然和 node 端有所差别,但是思想都是一样的。无非也是使用 MySQL 的查询结果, 拼装成前端所需要的数据。并进行返回。
点击下载本节的例子代码 blueprint/simple。
点击下载本节的例子代码。
点击下载本节的例子代码。
点击下载本节的例子代码。
点击下载本节的例子代码。
点击下载本节的例子代码。
点击下载本节的例子代码。
点击下载本节的例子代码 blueprint/complex。
数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。详细的合并规则如下:首先判断 mixin 中的数据类型和组件实例对象上的数据类型是否相同;如果不同,组件实例上的数据将覆盖 mixin 上的数据;如果相同,判断是否为 Object 的数据格式;如果不是 Object 的数据格式,组件实例上的数据将覆盖 mixin 上的数据;如果是 Object 的数据格式,从第一步开始循环判断 Object 的每一个属性。具体示例:687代码解释:JS 代码第 3-15 行,定义了一个混入对象 myMixin,并定义了数据 data。JS 代码第 18 行,通过组件实例上的 mixins 属性引入 myMixin。JS 代码第 19-30 行,定义了组件实例上的数据 data。根据之前我们学习的合并规则,得到的最终数据 data 格式如下:data() { return { isOpen: true, date: new Date().toLocaleString(), desc: { author: { name: 'Imooc', age: '20', location: '北京' } } }}
通常不会手动对代码去进行压缩,都会借助自动化的工具。代码进行压缩后,体积会有显著的变化,如 3.5.0 版本 jquery 未压缩的体积大概是 280KB ,压缩后大约为 80KB。代码压缩不仅仅是去除了空格,还会改变语法结构,但通常不影响执行结果。如以下函数:function encrypt(number) { number += 10; return number / 2 - 1;}压缩后的代码可能是这样的:function encrypt(n){return n+=10,n/2-1}这是一个简单的数字加密函数,利用逗号表达式的特性,就可以用于在函数中对连续的几个表达式进行压缩,最后一个表达式的结果就会是函数的返回值。
下面的代码演示了如何在 TypeScript 中使用混入:// Disposable Mixinclass Disposable { isDisposed!: boolean dispose() { this.isDisposed = true }}// Activatable Mixinclass Activatable { isActive!: boolean; activate() { this.isActive = true } deactivate() { this.isActive = false }}class SmartObject{ constructor() { setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500) } interact() { this.activate() } // Disposable isDisposed: boolean = false dispose!: () => void // Activatable isActive: boolean = false activate!: () => void deactivate!: () => void}applyMixins(SmartObject, [Disposable, Activatable])let smartObj = new SmartObject()setTimeout(() => smartObj.interact(), 2000)function applyMixins(derivedCtor: any, baseCtors: any[]) { baseCtors.forEach(baseCtor => { Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => { derivedCtor.prototype[name] = baseCtor.prototype[name] }) })}
在开发过程中会遇到一个很常见的需求,我们想获取一个值,但不能直接拿到,我们只能先请求一个接口如:api_1,获取这个值的接口地址如:api_2。然后,请求 api_2 接口才能获取这个值。这是一个典型的需要异步回调才能完成的功能。在学习 Promise 的时候我们也针对这样的情况,我们可以使用 Promise 来完成这样的功能:var promise = function (url) { return new Promise((resolve, reject) => { ajax(url, (data) => { resolve(data) // 成功 }, (error) => { reject(error) // 失败 }) })} promise('api_1').then(res1 => { promise(res1).then(res2 => { console.log(res2) })})从上面的代码中可以看出,在这种情况下,使用 Promise 好像并没有解决回调地狱的问题。那如何解决这种问题呢?我们想到了 Generator 函数具有暂停功能,那是不是我们可以让请求 api_2 接口时暂停,等到 api_1 请求成功获取到地址后再去请求呢?按照这个思路我们可以有下面的代码:const ajax = function(api) { return new Promise((resolve, reject) => { setTimeout(() => { if (api === 'api_1') { resolve('api_2'); } if (api === 'api_2') { resolve(100); } }, 0) })}function * getValue() { const api = yield ajax('api_1'); const value = yield ajax(api); return value;}console.log(getValue()); // Object [Generator] {}上面的代码是我们模拟 ajax 请求,通过使用生成器函数写出的代码让我们感觉有了同步的感觉,但是这样去执行 getValue 函数是不会得到结果的。那么我们要怎样去获得结果呢?根据生成器函数的特点,可以这样写:let it = getValue();let { value } = it.next();value.then((data) => { let { value } = it.next(data); value.then((data) => { Console.log(data); });});从上面的代码中看出还是有嵌套,好像并没有解决问题。但如果你细心,你会发现每个回调的逻辑基本都是一样的。那么我们能不能对这样的嵌套函数进行封装呢?答案当然是可以的,有个库就专门解决了这个痛点 —— co 库,有兴趣的可以去研究一下这个库,代码很少,下面我们就来封装一个这样的库。先让我们看看 co 库是怎么使用的:co(getValue()).then(res => { console.log(res);})从上面的代码中可以看出,把函数传入进去,并让函数执行,然后在 then 的成功回调中可以获取 getValue 函数返回的最终结果。这样非常清晰地解决了上面我们需要手动执行的方法,下面我来分析一下具体的实现步骤:从上面的用法可以看出,co 返回的是一个 Promise 实例,所以我们需要返回一个 new Promise() 实例;传入的生成器函数执行后,我们可以调用 next () 函数拿到返回的值和是否执行完的状态,判断 done 如果是 true 时说明执行完了,可以执行 resolve;当生成器函数没有执行完时,这时我们就需要递归地去调用这个 next () 来执行下一步,因为传入的值是一个 Promise 实例,要想获取它的结果就需要链式调用 then 方法,然后拿到结果进行递归执行。有了上面的步骤分析,不难得到下面的代码:function co(it) { return new Promise((resolve, reject) => { function next(data) { let { value, done } = it.next(data); if (done) { resolve(value); } else { Promise.resolve(value).then(data => { next(data); }, reject) } } next(undefined); })}上面的代码中需要注意的是,如果 yield 返回的不是一个 Promise 对象时,我们对 value 使用了 Promise.resolve() 进行了包装,这样就可以处理返回一个普通值时没有 then 方法的问题。
大部分开发者都会合理、巧妙的运用 this 关键字。初学者容易在 this 指向上犯错,如下面这个 Vue 组件:<div id="app"></div><script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script><script> // 发送post请求 const post = (cb) => { // 假装发了请求并在200ms后返回了服务端响应的内容 setTimeout(function() { cb([ { id: 1, name: '小红', }, { id: 2, name: '小明', } ]); }); }; new Vue({ el: '#app', data: function() { return { list: [], }; }, mounted: function() { this.getList(); }, methods: { getList: function() { post(function(data) { this.list = data; console.log(this); this.log(); // 报错:this.log is not a function }); }, log: function() { console.log('输出一下 list:', this.list); }, }, });</script>这是初学 Vue 的同学经常碰到的问题,为什么这个 this.log() 会抛出异常,打印了 this.list 似乎也是正常的。这其实是因为传递给 post 方法的回调函数,拥有自己的 this,有关内容可以查阅 this章节。不光在这个场景下,其他类似的场景也要注意,在写回调函数的时候,如果在回调函数内要用到 this,就要特别注意一下这个 this 的指向。可以使用 ES6 的箭头函数 或者将需要的 this 赋值给一个变量,再通过作用域链的特性访问即可:<div id="app"></div><script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script><script> // 发送post请求 const post = (cb) => { // 假装发了请求并在200ms后返回了服务端响应的内容 setTimeout(function() { cb([ { id: 1, name: '小红', }, { id: 2, name: '小明', } ]); }); }; new Vue({ el: '#app', data: function() { return { list: [], }; }, mounted: function() { this.getList(); }, methods: { getList: function() { // 传递箭头函数 post((data) => { this.list = data; console.log(this); this.log(); // 报错:this.log is not a function }); // 使用保留 this 的做法 // var _this = this; // post(function(data) { // _this.list = data; // console.log(this); // _this.log(); // 报错:this.log is not a function // }); }, log: function() { console.log('输出一下 list:', this.list); }, }, });</script>这个问题通常初学者都会碰到,之后慢慢就会形成习惯,会非常自然的规避掉这个问题。
Function 构造函数创建一个新的 Function 对象。直接调用此构造函数可用动态创建函数,但会遭遇来自 eval 的安全问题和相对较小的性能问题。—— MDNFunction 可以用来创建函数,JavaScript 中的所有函数,都是 Function对象。
由于学习 for each 循环需要一些数组和集合的前置知识,我们将会在 Java 数组小节举例讲解。
首先,为了演示方便,我们定义一个路由规则,定义代码如下:<?phpuse think\facade\Route;Route::get('info','Test/getInfo');Tips: 其中 info 表示路由名,这是一个 GET 请求方式,Test 表示控制器名,getInfo 表示 Test 控制器下的方法名。可以直接在控制器方法的参数中注入 Request 类对象,参考代码如下:<?phpnamespace app\controller;use app\BaseController;use think\Request;class Test extends BaseController{ public function getInfo(Request $request){ halt($request); }}Tips: 其中 Request 表示请求对象,这是通过依赖注入进来的,halt() 方法是打印内容并结束,$request 表示 Request 对象。执行结果如下图所示:Tips: 如图所示表示打印的 Request 对象的信息,其中包含了全部的请求信息。
data 属性里面定义的是页面的变量,在data里面定义的变量,我们应该怎样展示在页面上面呢?是在 template 标签中,通过 {{ mark }} 来引用在data里面定义的变量。在 script 标签中,通过 this.mark 来引用在data里面定义的变量。data 属性必须是一个函数,不然 vue 实例之间可能会相互影响,下面我们来看看正确的使用方法和错误的使用方法。正确实例:data () { return { mark: 0 }}错误实例:data: { mark: 0}
如果在线查找示例遇到了网络问题,则我们可以下载示例代码后手动导入到 Android Studio 中。Google 把优质的示例代码都托管到了 GitHub 上,所以我们按如下步骤操作:从 GitHub 上 下载 Google Samples 代码:在 Android Studio 中 Import Project:
这个属性是 HTML5 中用于存储自定义属性值,自定义属性值用于方便开发者存储一些简单的数据内容,而不需从服务器端获取。在 HTML4 中自定义属性的方式很有可能会跟系统关键字冲突,而 data-* 会被客户端忽略。data- 后边必须至少有一个字符,不要包含大写字符;JavaScript 可以用 getAttribute 函数获取自定义属性;HTML5 原生函数支持使用 dataset / setAttribute 来 获取/操作自定义属性。下面是 JavaScrip t使用 getAttribute 函数获取自定义属性的例子:938以上示例通过 data-type 保存了无序列表中每个条目的类型值,通过点击列表条目可以弹出类型值。