`

原生AJAX或jQuery实现二级联动选择以及解析XML和JSON数据格式

    博客分类:
  • AJAX
阅读更多

原生AJAX或jQuery实现二级联动选择以及解析XML和JSON数据格式

本文以省和城市为例来实现二级联动选择框,包含了DOM4J生成XML数据的方式和使用JSONArray类生成JSON数据格式的方式。以及服务器返回的数据类型XML和JSON格式在JavaScript和jQuery中的解析方法。
项目包结构图:
ProName
|--src
|   |-- com
|        |--ajax
|            |--bean
|            |    |--City.java
|            |    |--CreateJSONObject.java
|            |--servlet
|                 |--SelectCityServlet.java
|--WebRoot
    |--js
    |    |--jquery.js
    |    |--selectCity.js
    |    |--selectCityjQuery.js
    |--WEB-INF
    |    |--c.tld
    |    |--web.xml
    |--selectCity.jsp

1. 页面代码(selectCity.jsp)

<%@ page language="java" import="java.util.*,com.ajax.bean.City"
	pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%
	String path = request.getContextPath();
	//初始化省份选择框数据
	List<City> provinceList = City.getProvinceList();
	request.setAttribute("provinceList", provinceList);
%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<title>省和城市的级联选择实例</title>
		<script type="text/javascript" src="js/jquery.js"></script>
		<script type="text/javascript" src="js/selectCity.js"></script>
		<script type="text/javascript" src="js/selectCityjQuery.js"></script>
	</head>
	<body>
		<p />
		一、AJAX原生方式实现省和城市的级联选择:
		<p />
		<table cellspacing="0" cellpadding="2" align="left" border="0">
			<tr>
				<td style="width: 20px">
					&nbsp;
				</td>
				<td>
					省份:&nbsp;
				</td>
				<td style="width: 100px">

					<select id="provinceIdSelect" style="width: 80px"
						onchange="selectProvince()">
						<option value="" selected>
							全部
						</option>
						<c:if test="${!empty provinceList  }">
							<c:forEach var="province" items="${provinceList}">
								<option value="${province.id }" ${province.id==provinceId?'selected':''}>
									${province.name}
								</option>
							</c:forEach>
						</c:if>
					</select>
				</td>
				<td style="width: 20px">
					&nbsp;
				</td>
				<td>
					城市:&nbsp;
				</td>
				<td style="width: 100px">
					<select id="cityIdSelect" style="width: 80px">
						<option value="0">
							全部
						</option>
					</select>
				</td>
			</tr>
		</table>
		<br />
		<br />
		二、jQuery方式实现省和城市的级联选择:
		<p />
		<table cellspacing="0" cellpadding="2" align="left" border="0">
			<tr>
				<td style="width: 20px">
					&nbsp;
				</td>
				<td>
					省份:&nbsp;
				</td>
				<td style="width: 100px">
					<select id="provinceIdSelectJ" style="width: 80px"
						onchange="selectProvinceJ()">
						<option value="" selected>
							全部
						</option>
						<c:if test="${!empty provinceList  }">
							<c:forEach var="province" items="${provinceList}">
								<option value="${province.id }" ${province.id==provinceId?'selected':''}>
									${province.name}
								</option>
							</c:forEach>
						</c:if>
					</select>
				</td>
				<td style="width: 20px">
					&nbsp;
				</td>
				<td>
					城市:&nbsp;
				</td>
				<td style="width: 100px">
					<select id="cityIdSelectJ" style="width: 80px">
						<option value="0">
							全部
						</option>
					</select>
				</td>
			</tr>
		</table>
	</body>
</html>


2. JS代码
selectCity.js

//创建AJAX引擎   
function createXmlhttp () {
	var xhr;   
    if (window.XMLHttpRequest) {   
        //针对FireFox,Mozillar,Opera,Safari,IE7,IE8   
        xhr = new XMLHttpRequest();   
        //针对某些特定版本的mozillar浏览器的BUG进行修正   
        if (xhr.overrideMimeType) {   
            xhr.overrideMimeType("text/xml");   
        }   
    } else if (window.ActiveXObject) {   
         //针对IE6,IE5.5,IE5   
        //两个可以用于创建XMLHTTPRequest对象的控件名称,保存在一个js的数组中   
        //排在前面的版本较新   
        var activexName = ["MSXML2.XMLHTTP","Microsoft.XMLHTTP"];   
        for (var i = 0; i < activexName.length; i++) {   
            try{   
                //取出一个控件名进行创建,如果创建成功就终止循环   
                //如果创建失败,回抛出异常,然后可以继续循环,继续尝试创建   
                xhr = new ActiveXObject(activexName[i]);   
                break;   
            } catch(e){   
            }   
        }   
    } 
    return xhr; 
}   

var xmlhttp;  
//发送请求
function sendRequest(url ,content){
	xmlhttp = createXmlhttp (); 
	xmlhttp.onreadystatechange = processResponse;
	xmlhttp.open("post",url);
	xmlhttp.setRequestHeader("content-type","application/x-www-form-urlencoded");   
 	xmlhttp.send(content);   
}

//回调方法
function processResponse(){
	if (xmlhttp.readyState == 4 ) {
		if (xmlhttp.status == 200 ){
			//设置城市选择框为默认值
			setCityDefault();
			//获得服务器返回的XML,并转为DOC对象
			var xmldoc = xmlhttp.responseXML;
			//DOM解析XML
			domParseXml(xmldoc);
			//JSON格式解析
//			parseJson(xmlhttp.responseText);
		}
	}
}

//DOM解析XML
function domParseXml(xmldoc){
	
	//遍历服务器响应的XML,并创建对应option标签
	//获取显示城市的选择框
	var cityId_obj = document.getElementById("cityIdSelect");
	//获取具有指定标记名的所有元素节点
//	var city = xmldoc.getElementsByTagName("city");
	var city = xmldoc.selectNodes("/cities/city");
	for (var i=0; i<city.length; i++ ) {
		//获取节点文本
		var id_txt = city[i].childNodes[0].childNodes[0].data;  //data和nodeValue都可以
		var name_txt = city[i].childNodes[1].childNodes[0].nodeValue;
		//创建节点对象
		var id_obj = document.createTextNode(id_txt);
		var name_obj = document.createTextNode(name_txt);
		//创建城市<option>
		var cityOption = document.createElement("option");
		//设置value属性
		cityOption.setAttribute("value",id_obj);
		//设置name属性
		cityOption.appendChild(name_obj);
		cityId_obj.appendChild(cityOption);
	}
}

//解析JSON数据
function parseJson(obj){
	//通过eval() 函数可以将JSON字符串转化为对象
	var json  = eval(obj)
	//获取显示城市的选择框
	var cityId_obj = document.getElementById("cityIdSelect");
	//遍历JSON数组
	for (var ind in json) {
		//创建城市<option>
		var cityOption = document.createElement("option");
		//创建节点对象,将文本转为dom对象
		var id_obj = document.createTextNode(json[ind].id);
		var name_obj = document.createTextNode(json[ind].name);
		//设置value属性
		cityOption.setAttribute("value",id_obj);
		//设置name属性
		cityOption.appendChild(name_obj);
		cityId_obj.appendChild(cityOption);
	}
}

//改变省选择框触发事件,ajax异步请求
function selectProvince(){
	var provinceId_obj = document.getElementById("provinceIdSelect");
	if ( provinceId_obj.value != "" ) {
		var url = "selectCity";
		var content = "provinceId=" + provinceId_obj.value ;
		//发送AJAX请求
		sendRequest(url, content);
	} else {
		//设置城市选择框为默认值
		setCityDefault();
	}
}

//设置城市选择框为默认值
function setCityDefault(){
	//获取显示城市的选择框
	var cityId_obj = document.getElementById("cityIdSelect");
	//清除原来的select值
	cityId_obj.options.length=0;
	//添加默认的option标签
	//创建option标签
	var defOption_obj = document.createElement("option");
	defOption_obj.setAttribute("value","0");
	//设置默认选择
	var defName_obj = document.createTextNode("全部")
	defOption_obj.appendChild(defName_obj);
	cityId_obj.appendChild(defOption_obj);
}


selectCityjQuery.js,jquery版本为1.2.6

//创建异步请求
function selectProvinceJ(){
	var pidNode = $("#provinceIdSelectJ");
	
	if ( pidNode.val() != "" ) {
		//第一种:服务器以JSON响应
//		jsonResponseProcess(pidNode);

		//第二种:服务器以XML响应
		xmlResponseProcess(pidNode);
	} else {
		//设置城市选择框为默认值
		setCityDefaultJ();
	}
}

//请求后,返回JSON数据类型
function jsonResponseProcess(pidNode){
	var pid = pidNode.val();
	$.post("selectCity",
			{provinceId : pid},
			function(json){
				//获取显示城市的选择框
				var cidNode = $("#cityIdSelectJ");
				//清空之前内容
				cidNode.empty();
				$(json).each(function(i){
					cidNode.append("<option value='" + json[i].id + "'>" + json[i].name + "</option>" );
				});
			},
			"json"	//xml, html, script, json, text, _default		
		);
}

//请求后,返回XML数据类型
function xmlResponseProcess(pidNode){
	var pid = pidNode.val();
	$.post("selectCity",
			{provinceId : pid},
			function(xml){
				//获取显示城市的选择框
				var cidNode = $("#cityIdSelectJ");
				//清空之前内容
				cidNode.empty();
				var id_txt;
				var name_txt;
				$(xml).find("city").each(function(i){
					//children()先取得ID对象,text()再取值
					id_txt = $(this).children("id").text();
					//另一种取对象方法
					name_txt = $("name",this).text();
					cidNode.append("<option value='" + id_txt + "'>" + name_txt + "</option>" );
				});
			},
			"xml"	//xml, html, script, json, text, _default		
		);
}

//设置城市选择框为默认值
function setCityDefaultJ(){
	var cidNode = $("#cityIdSelectJ");
	//删除匹配的元素集合中所有的子节点。
	cidNode.empty();
	cidNode.append("<option>全部</option>");
}


3. Servlet/javaBean代码

SelectCityServlet.java

package com.ajax.servlet;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ajax.bean.City;
import com.ajax.bean.CreateJSONObject;
import com.ajax.bean.CreateXMLText;

/**
 * @author fzbtshy@163.com
 */
public class SelectCityServlet extends HttpServlet {

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// 生成XML和文本文件返回
		response.setContentType("text/xml");
		response.setCharacterEncoding("UTF-8");

		String provinceId = request.getParameter("provinceId");
		String provinceXml = null;
		List<City> cityList = null;

		try {
			if (null != provinceId && !"".equals(provinceId)) {
				// 根据id获取该省的城市列表
				cityList = City.getCityList(Long.valueOf(provinceId));
				
				//DOM4J方式生成XML
provinceXml  = dom4jToXml(cityList);
			
				//JSON数据格式返回
//				CreateJSONObject json = new CreateJSONObject();
//				provinceXml = json.nativeToJson(cityList);
//				provinceXml = json.jsonArrayToJson(cityList);
				
			}
			response.getWriter().print(provinceXml);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * DOM4J生成XML
	 * 
	 * @param list
	 * @return
	 */
	public String dom4jToXml(List<City> list) {
		String strXml = null;
		try {
			if (null != list && !list.isEmpty()) {
				DocumentFactory df = DocumentFactory.getInstance();
				// org.dom4j.Document doc = DocumentHelper.createDocument();
				org.dom4j.Document doc = df.createDocument("UTF-8");
				// 创建根节点
				org.dom4j.Element citiesElt = doc.addElement("cities");
	
				for (City po : list) {
					// 在节点<cities>下增加子节点<city>
					org.dom4j.Element cityElt = citiesElt.addElement("city");
	
					// 在节点<city>下增加子节点<id>
					org.dom4j.Element idElt = cityElt.addElement("id");
					idElt.addText(String.valueOf(po.getId()));
	
					// 在节点<city>下增加子节点<name>
					org.dom4j.Element nameElt = cityElt.addElement("name");
					nameElt.addText(po.getName());
				}
				
				// 无样式的
				strXml = doc.asXML();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("DOM4J:" + strXml);
		return strXml;
	}
}


City.java

package com.ajax.bean;

import java.util.ArrayList;
import java.util.List;

public class City {

	// 主键
	private Long id;

	// parentId为0代表是省份,否则为城市
	private Long parentId;

	// 名字
	private String name;

	/**
	 * 默认构造器
	 */
	public City() {

	}

	/**
	 * @param id
	 * @param parentId
	 * @param name
	 */
	public City(Long id, Long parentId, String name) {
		super();
		this.id = id;
		this.parentId = parentId;
		this.name = name;
	}

	/**
	 * @return the id
	 */
	public Long getId() {
		return id;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(Long id) {
		this.id = id;
	}

	/**
	 * @return the parentId
	 */
	public Long getParentId() {
		return parentId;
	}

	/**
	 * @param parentId
	 *            the parentId to set
	 */
	public void setParentId(Long parentId) {
		this.parentId = parentId;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name
	 *            the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "id=" + this.id + ",parentId=" + this.parentId + ",name="
				+ this.name;
	}
	
	/**
	 * 测试用 获取省份
	 * 
	 * @return
	 */
	public static List<City> getProvinceList() {
		List<City> provinceList = new ArrayList<City>();
		City city = new City(101L, 0L, "湖南省");
		provinceList.add(city);
		city = new City(102L, 0L, "广东省");
		provinceList.add(city);
		city = new City(103L, 0L, "浙江省");
		provinceList.add(city);
		return provinceList;
	}

	/**
	 * 测试用 获取城市
	 * 
	 * @return
	 */
	public static List<City> getCityList(Long provinceId) {
		List<City> cityList = new ArrayList<City>();
		City city = null;

		// 编写湖南的城市
		if (provinceId.equals(101L)) {
			city = new City(151L, 101L, "长沙市");
			cityList.add(city);
			city = new City(152L, 101L, "永州市");
			cityList.add(city);
			city = new City(153L, 101L, "衡阳市");
			cityList.add(city);
			city = new City(154L, 101L, "郴州市");
			cityList.add(city);
			city = new City(155L, 101L, "常德市");
			cityList.add(city);
		} else if (provinceId.equals(102L)) {
			// 编写广东的城市
			city = new City(171L, 102L, "广州市");
			cityList.add(city);
			city = new City(172L, 102L, "深圳市");
			cityList.add(city);
			city = new City(173L, 102L, "东莞市");
			cityList.add(city);
			city = new City(174L, 102L, "中山市");
			cityList.add(city);
			city = new City(175L, 102L, "佛山市");
			cityList.add(city);
			city = new City(176L, 102L, "江门市");
			cityList.add(city);
		} else if (provinceId.equals(103L)) {
			// 编写浙江的城市
			city = new City(191L, 103L, "杭州市");
			cityList.add(city);
			city = new City(192L, 103L, "宁波市");
			cityList.add(city);
		}
		return cityList;
	}

	public static void main(String[] args) {
		List<City> province = City.getProvinceList();
		for (City p : province) {
			System.out.println(p);
		}
		List<City> city = City.getCityList(101L);
		for (City c : city) {
			System.out.println(c);
		}
		
	}
}


CreateJSONObject.java

package com.ajax.bean;

import java.util.List;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
 * 生成json的数据格式
 * 
 * @author fzbtshy@163.com
 */

public class CreateJSONObject {

	// 采用json的数据格式返回对象信息
	// 冒号后可以为[{pid1:{id:"",name:""}, pid2:{id:"",name:""}}]
	// json格式:
	// [{
	// id: "city.getId()",
	// name: "city.getName()",
	// },
	// {
	// id: "city.getId()",
	// name: "city.getName()",
	// }]
	
	/**
	 * 字符串拼接的方式
	 * @param list
	 * @return 如:[{id:151,name:'长沙市'},{id:152,name:'永州市'}]
	 */
	public  String nativeToJson(List<City> list) {
		StringBuilder jsonStr = new StringBuilder(list.size());
		if (null != list && !list.isEmpty()) {
			int i=0;
			jsonStr.append("[");
			for (City po : list) {
				jsonStr.append("{id:")
						.append(po.getId())
						.append(",name:'")
						.append(po.getName())
						.append("'}");
				//最后不用加逗号
				if ( (++i) != list.size() ){
					jsonStr.append(",");
				}
			}
			jsonStr.append("]");
		}
		System.out.println("Native:" + jsonStr.toString());
		return jsonStr.toString();
	}
	
	/**
	 * json-lib.jar
	 * 依赖包:commons-logging.jar 
     *       common.lang.jar
     *       commons-beanutils.jar
     *       commons-collections.jar
     *       ezmorph.jar
	 * @param list
	 * @return 
	 */
	public  String jsonArrayToJson(List<City> list ) {
		//第一种方式,返回[{"parentId":101,"citys":[],"name":"长沙市","id":151},{"parentId":101,"citys":[],"name":"永州市","id":152}]
//		JSONArray js = JSONArray.fromObject(list);
		
		//第二种方式,返回[{"name":"长沙市","id":151},{"name":"永州市","id":152}]
		JSONArray js = new JSONArray();
		if (null != list && !list.isEmpty()) {
			JSONObject obj = null;
			for ( City po: list ){
				obj = new JSONObject();
				obj.put("id", po.getId());
				obj.put("name", po.getName());
				js.add(obj);
				obj = null;
			}
		}
		System.out.println("JSONArray:" + js.toString());
		return js.toString();
	}
	
	public static void main(String[] args) {
		List<City> list = City.getCityList(101L);
		CreateJSONObject json = new CreateJSONObject();
		json.nativeToJson(list);
		json.jsonArrayToJson(list);
		
	}
} 


4. web.xml

<servlet>
		<servlet-name>SelectCity</servlet-name>
		<servlet-class>com.ajax.SelectCityServlet</servlet-class>
	</servlet>
<servlet-mapping>
		<servlet-name>SelectCity</servlet-name>
		<url-pattern>/selectCity</url-pattern>
	</servlet-mapping>

 

 

分享到:
评论

相关推荐

    java+Ajax实现省市地三级联动

    总的来说,"java+Ajax实现省市地三级联动"是一个典型的前后端交互示例,它利用了Java Servlet处理HTTP请求和数据库操作,Ajax提供异步数据交换,JSON进行数据格式化,以及JavaScript处理前端的动态显示。这种技术...

    Ajax实现二级/三级联动下拉框---servlet版

    在Web开发中,二级或三级联动下拉框是一种常见的交互设计,主要用于展示层次关系的数据,如省份-城市-区县的区域选择。本教程将详细讲解如何使用Ajax和Servlet技术来实现这一功能。 首先,我们需要了解Ajax...

    纯ajax二级联动菜单

    在不刷新整个页面的情况下,通过Ajax(异步JavaScript和XML)技术,用户选择一级菜单后,二级菜单会根据一级菜单的选择动态加载相关数据,提供更加流畅的用户体验。 【描述】:这个项目是为初学者设计的,旨在教授...

    基于javaweb和ajax的省市联动实现

    实现这一功能的核心技术是JavaScript的Ajax(异步JavaScript和XML)以及JSON(JavaScript Object Notation)数据格式。 Ajax是Web2.0技术的重要组成部分,它通过在后台与服务器进行少量数据交换,使网页实现局部...

    jQuery + Ajax + json 级联

    在jQuery和Ajax的帮助下,我们可以实现这样的功能:当用户更改第一个下拉列表时,通过Ajax发送一个请求到服务器,服务器根据请求返回JSON格式的更新数据,然后前端使用jQuery解析JSON并更新第二个下拉列表。...

    ajax三级联动

    在网页开发中,"ajax三级联动"是一种常见的交互设计,主要应用于下拉菜单或选择框,如城市选择,其中包含省、市、区三个级别。这种功能能够为用户提供流畅的体验,无需每次选择都刷新整个页面,提高了网页的响应速度...

    从数据库中读取的二级联动菜单(ajax)

    5. **返回数据格式**:服务器返回的数据可以是JSON(JavaScript Object Notation),这是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。JSON格式的数据可以直接被JavaScript对象化,方便...

    自己手写的三级联动

    在三级联动的实现中,Ajax常用于在用户改变一级或二级菜单选择时,异步地向服务器发送请求,获取新的关联数据,然后更新相应的下拉菜单。 PHP(Hypertext Preprocessor)是一种广泛应用的开源脚本语言,特别适合于...

    下拉四级联动插件

    3. **JSON**:服务器返回的数据通常以JSON格式,因为它轻量、易于解析,并且JavaScript原生支持。JSON数据结构可以方便地表示四级联动中的层级关系。 4. **HTML/CSS**:HTML用于构建页面结构,CSS负责样式和布局。...

    java Ajax三级联动--地区 省 市 区县

    4. **JSON响应**:后端将查询结果转换为JSON格式,这是JavaScript原生支持的数据交换格式,方便前端解析。然后,服务器将JSON数据作为响应返回给前端。 5. **前端处理响应**:前端接收到JSON响应后,解析出数据,...

    韩顺平AJAX和jquery笔记整理

    与GET请求相比,POST请求能够发送更多的数据,数据格式可以是表单数据也可以是JSON等,并且数据发送到服务器后的内容不会保留在浏览器历史或WEB服务器日志中,安全性更高。 AJAX处理返回XML和JSON是两种常见的数据...

    javaweb省市县三级联动 Ajax 使用javweb 和 ajax 相结合, 实现省市县三级联动.zip

    - JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。在本例中,服务器返回的县列表是以JSON数组的形式,如:`[{"id":1,"name":"县1"},{"id":2,"name":...

    php_ajax_三级下拉联动

    5. JavaScript解析返回的JSON数据,动态创建并填充二级“城市”下拉菜单。 6. 当用户在“城市”下拉菜单中选择后,重复上述步骤获取并展示三级“区县”选项。 总的来说,“php_ajax_三级下拉联动”是Web开发中的一...

    ajax城市三级联动

    实现这个功能,可以使用jQuery的`$.ajax()`或`$.getJSON()`等封装好的方法,或者使用原生的XMLHttpRequest对象。同时,为了兼容性考虑,可以使用`fetch` API或者`axios`等库。 对于文件`ajx`,可能包含HTML模板、...

    c#省市县三级联动

    使用JSON格式进行数据传输,因为JSON轻量、易读,并且C#和JavaScript都支持原生解析。后端将XML数据转换为JSON格式,前端接收后解析并填充到下拉菜单。 6. **性能优化**: - 数据缓存:为了提高性能,可以将常用...

    国家、州(省)、城市AJAX三级联动

    在IT行业中,构建一个高效的用户界面常常涉及到数据的动态加载和交互,这通常通过使用AJAX(Asynchronous JavaScript and XML)技术实现。本项目“国家、州(省)、城市AJAX三级联动”就是一个典型的应用实例,它...

    jQuery模拟select下拉框三级城市联动代码.zip

    在网页开发中,"jQuery模拟select下拉框三级城市联动代码"是一种常见的交互设计,用于实现用户在选择一级城市后,自动更新二级城市列表,接着选择二级城市后,再动态加载三级城市的联动效果。这种技术提高了用户体验...

    AJAX+省市县联动+无刷新+C#源码

    服务器端代码通常负责查询数据库以获取相应的省市县数据,并将其封装成JSON或XML格式,以便AJAX请求返回时能正确解析。 具体实现步骤如下: 1. **前端HTML**:创建省市县的HTML元素,通常是下拉列表(`&lt;select&gt;`)...

Global site tag (gtag.js) - Google Analytics