可以!通过 webViewObject.EvaluateJS() 可以完全控制网页的列表。下面给你完整方案:
一、HTML页面结构
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>列表管理</title>
<style>
.list-container {
width: 100%;
max-width: 600px;
margin: 20px auto;
}
.list-item {
padding: 10px;
margin: 5px 0;
background: #f0f0f0;
border-radius: 5px;
display: flex;
justify-content: space-between;
align-items: center;
}
.delete-btn {
background: #ff4444;
color: white;
border: none;
padding: 5px 10px;
border-radius: 3px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="list-container">
<h2>商品列表</h2>
<ul id="productList"></ul>
</div>
<script>
// 添加列表项
function addItem(id, name, price) {
var list = document.getElementById('productList');
var li = document.createElement('li');
li.className = 'list-item';
li.id = 'item-' + id;
li.innerHTML = `
<div>
<strong>${name}</strong>
<span style="color: #666;"> - ¥${price}</span>
</div>
<button class="delete-btn" onclick="deleteItemAndNotify('${id}')">删除</button>
`;
list.appendChild(li);
// 通知Unity添加成功
Unity.call('itemAdded:' + id);
}
// 删除列表项
function deleteItem(id) {
var item = document.getElementById('item-' + id);
if (item) {
item.remove();
return true;
}
return false;
}
// 删除并通知Unity
function deleteItemAndNotify(id) {
if (deleteItem(id)) {
Unity.call('itemDeleted:' + id);
}
}
// 修改列表项
function updateItem(id, name, price) {
var item = document.getElementById('item-' + id);
if (item) {
item.querySelector('div').innerHTML = `
<strong>${name}</strong>
<span style="color: #666;"> - ¥${price}</span>
`;
Unity.call('itemUpdated:' + id);
return true;
}
return false;
}
// 清空列表
function clearList() {
document.getElementById('productList').innerHTML = '';
Unity.call('listCleared');
}
// 批量添加
function addItems(jsonArray) {
var items = JSON.parse(jsonArray);
items.forEach(function(item) {
addItem(item.id, item.name, item.price);
});
}
// 获取列表数据(返回给Unity)
function getListData() {
var list = document.getElementById('productList');
var items = [];
list.querySelectorAll('.list-item').forEach(function(li) {
items.push({
id: li.id.replace('item-', ''),
name: li.querySelector('strong').textContent,
price: li.querySelector('span').textContent
});
});
Unity.call('listData:' + JSON.stringify(items));
}
</script>
</body>
</html>
二、Unity C# 控制代码
using UnityEngine;
using System.Collections.Generic;
using Newtonsoft.Json; // 或使用 JsonUtility
public class WebViewListController : MonoBehaviour
{
private WebViewObject webViewObject;
void Start()
{
// 初始化WebView(参考你的示例代码)
InitWebView();
}
void InitWebView()
{
webViewObject = gameObject.AddComponent<WebViewObject>();
webViewObject.Init(
cb: (msg) =>
{
Debug.Log($"JS消息: {msg}");
HandleJSMessage(msg);
},
ld: (msg) =>
{
Debug.Log("页面加载完成");
// 页面加载后初始化数据
InitListData();
}
);
webViewObject.SetMargins(0, 0, 0, 0);
webViewObject.SetVisibility(true);
webViewObject.LoadURL("file://" + Application.streamingAssetsPath + "/list.html");
}
// 处理来自JS的消息
void HandleJSMessage(string msg)
{
if (msg.StartsWith("itemAdded:"))
{
string id = msg.Replace("itemAdded:", "");
Debug.Log($"商品 {id} 添加成功");
}
else if (msg.StartsWith("itemDeleted:"))
{
string id = msg.Replace("itemDeleted:", "");
Debug.Log($"商品 {id} 已删除");
OnItemDeleted(id);
}
else if (msg.StartsWith("listData:"))
{
string json = msg.Replace("listData:", "");
Debug.Log($"列表数据: {json}");
}
}
// ========== Unity调用JS:列表操作 ==========
// 添加单个商品
public void AddProduct(string id, string name, float price)
{
string js = $"addItem('{id}', '{EscapeJS(name)}', {price});";
webViewObject?.EvaluateJS(js);
}
// 删除商品
public void DeleteProduct(string id)
{
string js = $"deleteItem('{id}');";
webViewObject?.EvaluateJS(js);
}
// 修改商品
public void UpdateProduct(string id, string name, float price)
{
string js = $"updateItem('{id}', '{EscapeJS(name)}', {price});";
webViewObject?.EvaluateJS(js);
}
// 清空列表
public void ClearList()
{
string js = "clearList();";
webViewObject?.EvaluateJS(js);
}
// 批量添加商品
public void AddProductsBatch(List<Product> products)
{
string json = JsonConvert.SerializeObject(products);
// JSON中的引号需要转义
json = json.Replace("\"", "\\\"");
string js = $"addItems(\"{json}\");";
webViewObject?.EvaluateJS(js);
}
// 获取列表数据
public void GetListData()
{
string js = "getListData();";
webViewObject?.EvaluateJS(js);
}
// ========== 初始化数据示例 ==========
void InitListData()
{
// 方式1:单个添加
AddProduct("001", "iPhone 15", 5999);
AddProduct("002", "iPad Pro", 6799);
AddProduct("003", "MacBook Air", 9999);
// 方式2:批量添加
var products = new List<Product>
{
new Product { id = "004", name = "AirPods", price = 1299 },
new Product { id = "005", name = "Apple Watch", price = 2999 }
};
// AddProductsBatch(products);
}
// 响应删除事件
void OnItemDeleted(string id)
{
// 这里可以同步更新Unity的数据
Debug.Log($"同步删除Unity数据: {id}");
}
// JS字符串转义
string EscapeJS(string text)
{
return text.Replace("'", "\\'").Replace("\n", "\\n");
}
// ========== 测试按钮 ==========
void OnGUI()
{
if (GUI.Button(new Rect(10, 10, 150, 50), "添加商品"))
{
AddProduct("999", "测试商品", 99.99f);
}
if (GUI.Button(new Rect(10, 70, 150, 50), "删除商品001"))
{
DeleteProduct("001");
}
if (GUI.Button(new Rect(10, 130, 150, 50), "修改商品002"))
{
UpdateProduct("002", "iPad Pro 2024", 7999);
}
if (GUI.Button(new Rect(10, 190, 150, 50), "清空列表"))
{
ClearList();
}
if (GUI.Button(new Rect(10, 250, 150, 50), "获取列表数据"))
{
GetListData();
}
}
}
// 商品数据类
[System.Serializable]
public class Product
{
public string id;
public string name;
public float price;
}
三、高级用法:带动画效果
// 添加商品(带动画)
function addItemWithAnimation(id, name, price) {
var list = document.getElementById('productList');
var li = document.createElement('li');
li.className = 'list-item';
li.id = 'item-' + id;
li.style.opacity = '0';
li.style.transform = 'translateX(-50px)';
li.innerHTML = `
<div>
<strong>${name}</strong>
<span style="color: #666;"> - ¥${price}</span>
</div>
<button class="delete-btn" onclick="deleteItemAndNotify('${id}')">删除</button>
`;
list.appendChild(li);
// 动画效果
setTimeout(function() {
li.style.transition = 'all 0.3s ease';
li.style.opacity = '1';
li.style.transform = 'translateX(0)';
}, 10);
Unity.call('itemAdded:' + id);
}
// 删除商品(带动画)
function deleteItemWithAnimation(id) {
var item = document.getElementById('item-' + id);
if (item) {
item.style.transition = 'all 0.3s ease';
item.style.opacity = '0';
item.style.transform = 'translateX(50px)';
setTimeout(function() {
item.remove();
}, 300);
return true;
}
return false;
}
四、实战场景示例
场景1:网络请求后更新列表
async void LoadProductsFromServer()
{
// 从服务器获取数据
string json = await GetProductsFromAPI();
var products = JsonConvert.DeserializeObject<List<Product>>(json);
// 先清空列表
ClearList();
// 等待一帧确保清空完成
await System.Threading.Tasks.Task.Delay(100);
// 批量添加到网页
AddProductsBatch(products);
}
场景2:搜索过滤列表
// 在HTML中添加搜索功能
function filterList(keyword) {
var items = document.querySelectorAll('.list-item');
items.forEach(function(item) {
var name = item.querySelector('strong').textContent;
if (name.toLowerCase().includes(keyword.toLowerCase())) {
item.style.display = 'flex';
} else {
item.style.display = 'none';
}
});
}
// Unity端调用搜索
public void SearchProducts(string keyword)
{
string js = $"filterList('{EscapeJS(keyword)}');";
webViewObject?.EvaluateJS(js);
}
场景3:列表项点击事件
// 修改HTML,添加点击事件
li.onclick = function() {
Unity.call('itemClicked:' + id);
};
// Unity处理点击
void HandleJSMessage(string msg)
{
if (msg.StartsWith("itemClicked:"))
{
string id = msg.Replace("itemClicked:", "");
ShowProductDetail(id);
}
}
五、注意事项
-
字符串转义:传递包含特殊字符(引号、换行)的字符串时要转义
-
异步问题 :
EvaluateJS是异步的,连续调用可能需要延迟 -
性能优化:批量操作优于多次单个操作
-
错误处理:JS执行失败时Unity不会报错,需要JS端返回结果确认
// 带确认的操作
public void AddProductSafe(string id, string name, float price)
{
string js = $@"
try {{
addItem('{id}', '{EscapeJS(name)}', {price});
Unity.call('success:add:{id}');
}} catch(e) {{
Unity.call('error:' + e.message);
}}
";
webViewObject?.EvaluateJS(js);
}